Python为我们提供了在类中创建“private”方法和变量的能力,方法是在名称前加上双下划线,例如:__myPrivateMethod()。那么,如何解释这一点呢

>>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

>>> obj.myPublicMethod()
public method

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

>>> obj._MyClass__myPrivateMethod()
this is private!!

怎么回事?!

我会为那些不太明白这一点的人解释一下。

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

我用一个公共方法和一个私有方法创建一个类并实例化它。

接下来,我调用它的公共方法。

>>> obj.myPublicMethod()
public method

接下来,我尝试调用它的私有方法。

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

这里一切都很好;我们不能称之为“私人”。事实上不是。在对象上运行dir()揭示了Python为所有“私有”方法神奇地创建的一个新的神奇方法。

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

此新方法的名称始终是下划线,后跟类名,后跟方法名。

>>> obj._MyClass__myPrivateMethod()
this is private!!

封装就这么多了,是吗?

无论如何,我一直听说Python不支持封装,所以为什么还要尝试呢?有什么好处?


当前回答

这并不是说在任何语言(C++中的指针算法和.NET/Java中的反射)中都无法避免成员的隐私。

关键是,如果您尝试意外调用私有方法,就会出现错误。但如果你想射自己的脚,那就去做吧。

你不会试图通过OO封装来保护你的东西,是吗?

其他回答

为什么Python的“私有”方法实际上不是私有的?

据我所知,他们不可能是私人的。如何才能强制实施隐私?

显而易见的答案是“私有成员只能通过self访问”,但这行不通——self在Python中并不特殊。它只是函数的第一个参数的常用名称。

重要说明:

__name形式的任何标识符(至少两个前导下划线,最多一个尾随下划线)都会公开替换为_classname__name,其中classname是当前类名,去掉前导下划线。

因此,__name不能直接访问,但可以作为_classname__name访问。

这并不意味着您可以保护您的私有数据,因为它可以通过更改变量的名称轻松访问。

资料来源:

官方文件中的“私人变量”部分:https://docs.python.org/3/tutorial/classes.html#tut-私人的,私人的

实例

class Cat:
    def __init__(self, name='unnamed'):
        self.name = name
    def __print_my_name(self):
        print(self.name)
        
        
tom = Cat()
tom.__print_my_name() #Error
tom._Cat__print_my_name() #Prints name

对于Python 3.4,这是一种行为:

>>> class Foo:
        def __init__(self):
                pass
        def __privateMethod(self):
                return 3
        def invoke(self):
                return self.__privateMethod()


>>> help(Foo)
Help on class Foo in module __main__:

class Foo(builtins.object)
 |  Methods defined here:
 |
 |  __init__(self)
 |
 |  invoke(self)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

 >>> f = Foo()
 >>> f.invoke()
 3
 >>> f.__privateMethod()
 Traceback (most recent call last):
   File "<pyshell#47>", line 1, in <module>
     f.__privateMethod()
 AttributeError: 'Foo' object has no attribute '__privateMethod'

从9.6开始。专用变量:

注意,损坏规则的设计主要是为了避免事故;仍然可以访问或修改被认为是私有的变量。这甚至可以在特殊情况下使用,例如在调试器中。

当模块属性名称以单个下划线(例如_foo)开头时,也存在类似的行为。

使用from*方法时,这样命名的模块属性不会复制到导入模块中,例如:

from bar import *

然而,这是一种惯例,而不是语言限制。这些不是私有属性;它们可以被任何进口商引用和操纵。一些人认为,正因为如此,Python无法实现真正的封装。

当我第一次从Java学习Python时,我讨厌这一点。这把我吓死了。

今天,这可能是我最喜欢Python的一件事。

我喜欢在一个平台上,人们相互信任,不需要在代码周围筑起难以逾越的墙。在强封装语言中,如果API存在错误,并且您已经发现了问题所在,那么您可能仍然无法解决它,因为所需的方法是私有的。在Python中,态度是:“确定”。如果你认为你了解情况,也许你甚至读过,那么我们只能说“祝你好运!”。

请记住,封装与“安全性”,或者让孩子们远离草坪,甚至没有微弱的关联。这只是另一种模式,应该用来使代码库更容易理解。