首页 文章

为什么Python 's ' private'方法实际上不是私有的?

提问于
浏览
544

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 "", line 1, in 
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 "", line 1, in 
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

这里的一切看起来都很好;我们're unable to call it. It is, in fact, ' private '. Well, actually it isn' t . 在对象上运行dir()会显示一个新的神奇方法,python为你的所有'private'方法神奇地创建 .

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

这个新方法的名称始终是下划线,后跟类名,后跟方法名 .

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

封装这么多,嗯?

无论如何,我总是听说Python不支持封装,为什么要试试呢?是什么赋予了?

11 回答

  • 11

    使用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'
    

    https://docs.python.org/3/tutorial/classes.html#tut-private

    请注意,修剪规则主要是为了避免事故;它仍然可以访问或修改被视为私有的变量 . 这在特殊情况下甚至可能很有用,例如在调试器中 .

    即使问题很老,我也希望我的代码片段能够提供帮助 .

  • 133

    这并不像你绝对不能用任何语言来解决成员的私密性(C中的指针算术,.NET / Java中的思考) .

    关键是如果您尝试偶然调用私有方法,则会出现错误 . 但如果你想用脚射击自己,那就去做吧 .

    编辑:你不试图通过OO封装来保护你的东西,对吗?

  • 12

    私人功能的例子

    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 begining
                matched = re.match( '^self\.', function_call )
                if not matched :
                    print 'This is Private Function, Go Away'
                    return
            except :
                print 'This is Private Function, Go Away'
                return
    
            # This is the real Function, only accessible inside class #
            print 'Hey, Welcome in to function'
    
        def public_function ( self ) :
            # i can call private function from inside the class
            self.private_function()
    
    ### End ###
    
  • 31

    当我第一次从Java转到Python时我就是这个 . 它让我害怕死亡 .

    今天它可能只是关于Python的一件事 I love most .

    我喜欢在一个平台上,人们互相信任,并且不觉得他们需要围绕代码 Build 难以穿透的墙 . 在强封装的语言中,如果API有错误,并且您已经找出问题所在,那么您可能仍然无法解决它,因为所需的方法是私有的 . 在Python中,态度是:“确定” . 如果你认为你了解情况,也许你甚至已经阅读过,那么我们所能说的就是“祝你好运!” .

    请记住,封装甚至与“安全”无关,或者让孩子们远离草坪 . 它只是应该用于使代码库更容易理解的另一种模式 .

  • 84

    来自http://www.faqs.org/docs/diveintopython/fileinfo_private.html

    严格来说,私人方法可以在课堂外访问,但不容易访问 . Python中没有任何东西是真正私有的;在内部,私有方法和属性的名称在运行中被破坏和解除标记,使它们看起来无法通过给定的名称访问 . 您可以通过名称_MP3FileInfo__parse访问MP3FileInfo类的__parse方法 . 承认这很有趣,然后承诺永远不会在真正的代码中做到这一点 . 私有方法是私有的,但与Python中的许多其他东西一样,它们的私密性最终是一个惯例,而不是力 .

  • 203

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

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

    from bar import *
    

    但是,这是一种约定而不是语言约束 . 这些不是私人属性;它们可以被任何进口商引用和操纵 . 有人认为,由于这个原因,Python无法实现真正的封装 .

  • 2

    常用的短语是“我们都在这里同意成年人” . 通过预先添加单个下划线(不暴露)或双下划线(隐藏),您告诉您的类的用户您希望该成员以某种方式“私有” . 但是,除非他们有令人信服的理由(例如调试器,代码完成),否则你相信其他所有人都要负责任并尊重这一点 .

    如果你真的必须拥有私有的东西,那么你可以在扩展中实现它(例如在CP中用于CPython) . 但是,在大多数情况下,您只需学习Pythonic的做事方式 .

  • 134

    这只是其中一种语言设计选择 . 在某种程度上,他们是合理的 . 他们做到这一点你需要走得很远,试图调用这个方法,如果你真的非常需要它,你必须有一个很好的理由!

    作为可能的应用程序会想到调试挂钩和测试,当然负责任地使用 .

  • 12

    关于私有方法和属性的最重要的问题是告诉开发人员不要在类之外调用它,这是封装 . 人们可能会误解封装的安全性 . 当你故意使用你提到的语法(bellow)时,你不需要封装 .

    obj._MyClass__myPrivateMethod()
    

    我已经从C#和起初它对我来说也很奇怪,但过了一段时间我才明白,只有Python代码设计师对OOP的思考方式才有所不同 .

  • 3

    class.__stuff 命名约定让程序员知道他不打算从外部访问 __stuff . 名称错误使得任何人都不可能偶然做到这一点 .

    没错,你仍然可以解决这个问题,它比其他语言更容易(BTW也允许你这样做),但如果他关心封装,没有Python程序员会这样做 .

  • 506

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

    例如:

    >>> 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}
    

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

相关问题