这有什么问题?从客观和功能的角度来看?
import sys
class EncapsulationClass(object):
def __init__(self):
self.privates = ["__dict__", "privates", "protected", "a"]
self.protected = ["b"]
print self.privates
self.a = 1
self.b = 2
self.c = 3
pass
def __getattribute__(self, name):
if sys._getframe(1).f_code.co_argcount == 0:
if name in self.privates:
raise Exception("Access to private attribute \"%s\" is not allowed" % name)
else:
return object.__getattribute__(self, name)
else:
return object.__getattribute__(self, name)
def __setattr__(self, name, value):
if sys._getframe(1).f_code.co_argcount == 0:
if name in self.privates:
raise Exception("Setting private attribute \"%s\" is not allowed" % name)
elif name in self.protected:
raise Exception("Setting protected attribute \"%s\" is not allowed" % name)
else:
return object.__setattr__(self, name, value)
else:
return object.__setattr__(self, name, value)
example = EncapsulationClass()
example.a = 10 # Exception: Setting private attribute "a" is not allowed
example.b = 10 # Exception: Setting protected attribute "b" is not allowed
example.c = 10 # example.c == 10
example.__dict__["privates"] # Exception: Setting protected attribute "b" is not allowed
做这样的事情实际上会出现什么问题?
有没有更好的方法在Python中实现封装?
答案 0 :(得分:39)
Python有封装 - 你在课堂上使用它。
它没有的是访问控制,例如私有和受保护的属性。但是,在Python中,有一个属性命名约定来表示私有属性,方法是在属性前加一个或两个下划线,例如:
self._a
self.__a
单个下划线向用户表明某个属性应该被视为该类的私有属性,不应直接访问。
双下划线表示相同,但是,Python会稍微破坏属性名称以试图隐藏它。
class C(object):
def __init__(self):
self.a = 123 # OK to access directly
self._a = 123 # should be considered private
self.__a = 123 # considered private, name mangled
>>> c = C()
>>> c.a
123
>>> c._a
123
>>> c.__a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__a'
>>> c._C__a
123
您可以在上一个示例中看到该名称已从__a
更改为_C__a
,但在类中仍可以self.__a
进行访问。
答案 1 :(得分:1)
嗯,Python没有封装作为一种“哲学”决定,就像我们经常使用duck typing一样。我个人认为在Python代码中没有使用私有或受保护的参数。
说到你的代码,它似乎与以下getter和setter一起正常工作:
def set_a(self, v):
self.a = v
def get_a(self):
return self.a
如果您对__ getattribute __(self,name)的最后一行进行了以下修改:
return object.__getattribute__(self, name)
然而,如果您使用__作为私有变量的前缀,那么可以使用变量保护的概念,正如mhawke所提到的那样。此外,Daniel的评论指出了列表参数的限制。您可以通过在私人列表中添加“私人”和“受保护”来保持受保护的“获取/设置”行为。
答案 2 :(得分:0)
因此Python 3提供了3个级别的数据访问:
1.public(public,没有特殊语法,publicVariable)
2.protected(受保护,名称开头加一个下划线,_protectedVariable);
3.private(私有,名称开头有两个下划线__privateVariable)。
所以最后一个称为封装,这意味着限制对对象组件(变量,方法)的访问,因此您可以在类内部定义方法,因此用户既可以查看变量,甚至可以更改变量,并且如果要给用户这样的特权,就依赖于编程者,因此,简而言之,实际上它使编程者可以调用可以公开的内容和内部的东西
私人和公共场所是基本且经常使用的,这是一个示例
`
class phone:
name="sony" #this variable is public
__number= 201090943929 #this is private one ,and also my actual number heheheheeh boii
def print_name(self): #this is public method
print ('my phone name is:', self.name)
def __print_number(self): #and private method
print (self.__number)
#actually we(the programmer not the user)-while writing the code- can give the user the user the authority to only
#see the value of the variable ,even to modify it by defining a metod inside the class
def print_private_number(self):
return self.__number
def modify_private_number(self,newNumber):
self.__number=newNumber
print(newNumber)
#now u can both prnt and modify the mumber with only the following methods
my_phone=phone()
my_phone.print_name() #now i called the public function , and cam simply print it as it's public (can be accessed)
print (my_phone.name) #same as here with variable
#Now if we tried to retrive private data ,or run private method
#its gonna end up with an error
#print (my_phone.__number)
#my_phone.__print_number()
print (my_phone.print_private_number())
my_phone.modify_private_number(5)
#so what if the programmer didnt allow us to see the number
#is that the end of the road ? nah ,we still can crack the system and both read and modify the private variables n functions
#hmmm am not gonna call it crack coz the langauage itself provides the programmer with
#syntatic tool that circumvent encapsulation
print (my_phone._phone__number)
#my_phone._phone__print_name()
`
答案 3 :(得分:0)
在 Mark Lutz 的《Learning Python, Fifth edition》一书中,他提到了一种模拟类级别封装的方法,如下所示:
"""
Created on Sun Oct 4 10:16:30 2020
@author: Mark Lutz
A typical implementation of encapsulation in python,
to use, call:@private(‘var1’, ‘var2’...)
"""
def private(*values):
def decorator(cls):
class Proxy:
def __init__(self, *args, **kwargs):
self.inst = cls(*args, **kwargs)
def __call__(self, cls, *args, **kwargs):
return self.inst
def __getattr__(self, attr):
if attr in values:
raise AttributeError("Private valueiables are not accessible!")
else: return getattr(self.inst, attr)
def __setattr__(self, attr, val):
# Allow access inside the class
if attr == 'inst': self.__dict__[attr] = val
elif attr in values:
raise AttributeError("Private valueiables are not accessible!")
else: setattr(self.inst, attr, val)
def __str__(self):
return self.inst.__str__()
return Proxy
return decorator
这可用于类级封装(例如,限制类中变量或方法的访问)。
然而,对于模块级封装,我能想到的唯一方法是创建一个文件并编写init.py。但是,如果编写客户端程序的人知道您的文件/包的结构,这仍然无法阻止他们导入内容。