2014-10-06 62 views
5

这是怎么回事?从客观和功能角度来看?如何在Python中进行封装?

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中的封装?

+3

...你是什么意思?你认为什么是错的?它运行吗? – jonrsharpe 2014-10-06 12:53:34

+1

可能在[codereview](http://codereview.stackexchange.com/)中提出 – 2014-10-06 12:56:28

+0

它似乎工作正常,是的,但我经常看到有人说“python没有封装”,所以推测它不能“不要这样简单。 – will 2014-10-06 12:57:39

回答

31

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

我知道所有这一切,但这与我所谈论的并不完全相同,似乎有两种封装的定义。其中之一就是将几段数据打包成一个类,另一个是实际隐藏数据/使其无法访问。 '__a'的东西,我很好,但这不是我所追求的 - 我更感兴趣的是模仿在其他语言中看到的'private','protected'等变量修饰符。 – will 2014-10-06 13:12:25

+0

我对整个'__a'变量的理解只不过是让人们使用你的代码知道他们不是你打算在模块外部使用的变量 - 而且这样的人不会依赖它们,因为他们随时都有可能改变。 – will 2014-10-06 13:13:31

1

那么,Python没有封装作为一种“哲学”决定,就像我们用鸭子打字很多一样。就我个人而言,我没有看到在Python代码中使用私有或受保护参数的要点。

代码的说起来,这似乎很好地工作具有以下getter和setter方法:

def set_a(self, v): 
    self.a = v 

def get_a(self): 
    return self.a 

,如果你做如下修改__的getAttribute __(自我,名)的最后一行:

return object.__getattribute__(self, name) 

但是,您可以作为mhawke提到使用某种可变保护,如果你以__为前缀的私有变量概念。另外,Daniel的评论指出了你的列表参数的限制。您可以通过在私人列表中添加“私人”和“受保护”来保留受保护的“获取/设置”行为。