【发布时间】:2010-09-09 09:21:41
【问题描述】:
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 不支持封装,那么为什么还要尝试呢?什么给了?
【问题讨论】:
-
如果您使用反射,Java 或 C# 也是如此(这就是您在那里所做的)。
-
它是为单元测试目的而构建的,因此您可以使用该“hack”从外部对您的类的私有方法进行单元测试。
-
测试私有方法不是反模式吗?私有方法将在某些公共方法中使用,以确保它永远不会被使用。测试私有方法的正确方法(基于我迄今为止从 ThoughtWorks 学到的知识)是只为覆盖所有情况的公共方法编写测试。如果一切正常,您根本不需要从外部测试私有方法。
-
@VishnuNarang:是的,这是经常被教导的。但与往常一样,“总是这样做,从不那样做”几乎是“宗教”的方法是唯一“从不”好的事情。如果单元测试“仅”用于回归测试或测试公共 API,则不需要测试私有。但是,如果您进行单元测试驱动开发,那么在开发过程中测试私有方法是有充分理由的(例如,当很难通过公共接口模拟某些异常/极端参数时)。一些语言/单元测试环境不允许你这样做,恕我直言不好。
-
@MarcoFreudenberger 我明白你的意思。我确实有单元测试驱动开发的经验。通常,当模拟参数变得困难时,通常可以通过更改和改进设计来解决。我还没有遇到过设计完美但单元测试仍然很难避免测试私有方法的场景。我会留意这种情况。谢谢。如果您能分享一个场景以帮助我理解,我将不胜感激。
标签: python python-2.7 encapsulation information-hiding