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 "", 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'
这里的一切都很好看; 我们无法称呼它.事实上,它是"私人的".嗯,实际上并非如此.在对象上运行dir()会显示一个新的神奇方法,即python为所有"私有"方法创建神奇的方法.
>>> dir(obj) ['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']
这个新方法的名称始终是下划线,后跟类名,后跟方法名.
>>> obj._MyClass__myPrivateMethod() this is private!!
封装如此之多,嗯?
无论如何,我总是听说Python不支持封装,所以为什么要试试呢?是什么赋予了?
名称加扰用于确保子类不会意外地覆盖其超类的私有方法和属性.它的目的不是为了防止来自外部的故意访问.
例如:
>>> 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}
当然,如果两个不同的类具有相同的名称,它就会崩溃.
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 ###
当我第一次从Java转向Python时,我讨厌这个.它让我害怕死亡.
今天它可能只是我最喜欢Python 的一件事.
我喜欢在一个平台上,在这个平台上,人们相互信任,并且不觉得他们需要在代码周围建立难以穿透的墙.在强封装的语言中,如果API有错误,并且您已经找出问题所在,那么您可能仍然无法解决它,因为所需的方法是私有的.在Python中,态度是:"确定".如果你认为你了解情况,也许你甚至已经阅读过,那么我们所能说的就是"祝你好运!".
请记住,封装甚至与"安全"无关,或者让孩子远离草坪.它只是应该用于使代码库更容易理解的另一种模式.
来自http://www.faqs.org/docs/diveintopython/fileinfo_private.html
严格来说,私人方法可以在课堂外访问,但不容易访问.Python中没有任何东西是真正私有的; 在内部,私有方法和属性的名称在运行中被破坏和解开,使它们看起来无法通过给定的名称访问.您可以通过名称_MP3FileInfo__parse访问MP3FileInfo类的__parse方法.承认这很有趣,然后承诺永远不会在真正的代码中做到这一点.私有方法是私有的,但与Python中的许多其他东西一样,它们的私有性最终是一个惯例,而不是力.
常用的短语是"我们都是在这里同意成年人".通过预先添加单个下划线(不暴露)或双下划线(隐藏),您告诉您的类的用户您希望该成员以某种方式"私有".但是,除非他们有令人信服的理由(例如调试器,代码完成),否则你相信其他所有人都要负责任并尊重这一点.
如果你真的必须拥有私有的东西,那么你可以在扩展中实现它(例如在CP中用于CPython).但是,在大多数情况下,您只需学习Pythonic的做事方式.
这并不像你绝对不能用任何语言来解决成员的私密性(C++中的指针算术,.NET/Java中的思考).
关键是如果您尝试偶然调用私有方法,则会出现错误.但如果你想用脚射击自己,那就去做吧.
编辑:你没有尝试通过OO封装来保护你的东西,对吗?
该class.__stuff
命名约定可以让程序员知道他是不是要访问__stuff
外部.名称错误使得任何人都不可能偶然做到这一点.
没错,你仍然可以解决这个问题,它比其他语言更容易(BTW也允许你这样做),但如果他关心封装,没有Python程序员会这样做.
这只是其中一种语言设计选择.在某种程度上,他们是合理的.他们制作它所以你需要走得很远,试着调用这个方法,如果你真的非常需要它,你必须有一个很好的理由!
调试钩子和测试作为可能的应用程序浮现在脑海中,当然负责任地使用.
当模块属性名称以单个下划线(例如_foo)开头时,存在类似的行为.
使用该from*
方法时,不会将这样命名的模块属性复制到导入模块中,例如:
from bar import *
但是,这是一种约定而不是语言约束.这些不是私人属性; 它们可以被任何进口商引用和操纵.有人认为,由于这个原因,Python无法实现真正的封装.