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

新手上路,请多包涵

Python 使我们能够通过在名称前面加上双下划线来在类中创建“私有”方法和变量,例如: __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 不支持封装,那么为什么还要尝试呢?是什么赋予了?

原文由 willurd 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 723
2 个回答

名称加扰用于确保子类不会意外覆盖其超类的私有方法和属性。它的设计目的不是为了防止从外部故意访问。

例如:

 >>> class Foo(object):
...     def __init__(self):
...         self.__baz = 42
...     def foo(self):
...         print self.__baz
...
>>> class Bar(Foo):
...     def __init__(self):
...         super(Bar, self).__init__()
...         self.__baz = 21
...     def bar(self):
...         print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}

当然,如果两个不同的类具有相同的名称,它就会崩溃。

原文由 Alya 发布,翻译遵循 CC BY-SA 2.5 许可协议

私有函数示例

import re
import inspect

class MyClass:

    def __init__(self):
        pass

    def private_function(self):
        try:
            function_call = inspect.stack()[1][4][0].strip()

            # See if the function_call has "self." in the beginning
            matched = re.match( '^self\.', function_call)
            if not matched:
                print 'This is a private function. Go away.'
                return
        except:
            print 'This is a private function. Go away.'
            return

        # This is the real function, only accessible inside the class #
        print 'Hey, welcome in to the function.'

    def public_function(self):
        # I can call a private function from inside the class
        self.private_function()

### End ###

原文由 arun 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题