为什么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 "", 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不支持封装,所以为什么要试试呢? 是什么赋予了?
11个解决方案
506 votes
名称加扰用于确保子类不会意外地覆盖其超类的私有方法和属性。 它的目的不是为了防止来自外部的故意访问。
例如:
>>> 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 answered 2019-03-27T23:38:19Z
203 votes
私有功能的例子
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 ###
arun answered 2019-03-27T23:38:48Z
133 votes
来自[http://www.faqs.org/docs/diveintopython/fileinfo_private.html]
严格来说,私人方法是 只是在课堂之外 不容易进入。 没什么 Python是真正私密的;在内部, 私人方法和名称 属性被破坏和未被破坏 在飞行中让他们看起来 他们的名字无法进入。 您 可以访问的__parse方法 MP3FileInfo类的名称 _MP3FileInfo__parse。 承认这很有趣,然后承诺 从来没有,在真正的代码中做过。 私有方法是私有的 原因,但像许多其他事情一样 Python,他们的私密性是 最终是一个惯例,而不是 力。
xsl answered 2019-03-27T23:39:20Z
133 votes
当我第一次从Java转向Python时,我讨厌这个。 它让我害怕死亡。
今天它可能只是我最喜欢Python的一件事。
我喜欢在一个平台上,在这个平台上,人们相互信任,并且不觉得他们需要在代码周围建立难以穿透的墙。 在强封装的语言中,如果API有错误,并且您已经找出问题所在,那么您可能仍然无法解决它,因为所需的方法是私有的。 在Python中,态度是:“确定”。 如果你认为你了解情况,也许你甚至已经阅读过,那么我们所能说的就是“祝你好运!”。
请记住,封装甚至与“安全”无关,或者让孩子远离草坪。 它只是应该用于使代码库更容易理解的另一种模式。
Thomas Ahle answered 2019-03-27T23:40:06Z
84 votes
常用的短语是“我们都是在这里同意成年人”。 通过预先添加单个下划线(不暴露)或双下划线(隐藏),您告诉您的类的用户您希望该成员以某种方式“私有”。 但是,除非他们有令人信服的理由(例如,调试器,代码完成),否则您相信其他所有人都要负责任并尊重这一点。
如果你真的必须拥有私有的东西,那么你可以在扩展中实现它(例如在C for CPython中)。 但是,在大多数情况下,您只需学习Pythonic的做事方式。
Tony Meyer answered 2019-03-27T23:40:38Z
31 votes
这并不像你绝对无法绕过任何语言的成员私密性(C ++中的指针算术,.NET / Java中的思考)。
关键是如果您尝试偶然调用私有方法,则会出现错误。 但如果你想用脚射击自己,那就去做吧。
编辑:你没有尝试通过OO封装来保护你的东西,对吗?
Maximilian answered 2019-03-27T23:41:15Z
12 votes
当模块属性名称以单个下划线(例如_foo)开头时,存在类似的行为。
使用from*方法时,不会将名为此类的模块属性复制到导入模块中,例如:
from bar import *
但是,这是一种约定而不是语言约束。 这些不是私人属性; 它们可以被任何进口商引用和操纵。 有人认为,由于这个原因,Python无法实现真正的封装。
Ross answered 2019-03-27T23:41:54Z
12 votes
这只是其中一种语言设计选择。 在某种程度上,他们是合理的。 他们制作它所以你需要走得很远,试着调用这个方法,如果你真的非常需要它,你必须有一个很好的理由!
调试钩子和测试作为可能的应用程序浮现在脑海中,当然负责任地使用。
ctcherry answered 2019-03-27T23:42:26Z
11 votes
class.__stuff命名约定让程序员知道他不打算从外面访问__stuff。 名称错误使得任何人都不可能偶然做到这一点。
没错,你仍然可以解决这个问题,它比其他语言更容易(BTW也允许你这样做),但如果他关心封装,没有Python程序员会这样做。
Nickolay answered 2019-03-27T23:43:09Z
3 votes
使用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 "", line 1, in
f.__privateMethod()
AttributeError: 'Foo' object has no attribute '__privateMethod'
[https://docs.python.org/3/tutorial/classes.html#tut-private]
请注意,修剪规则主要是为了避免事故; 它仍然可以访问或修改被认为是私有的变量。 这甚至可以在特殊情况下使用,例如在调试器中。
即使问题很老,我也希望我的代码片段能够提供帮助。
Alberto answered 2019-03-27T23:43:54Z
1 votes
关于私有方法和属性的最重要的问题是告诉开发人员不要在类之外调用它,这是封装。 人们可能会误解封装的安全性。 当你故意使用你提到的语法(bellow)时,你不需要封装。
obj._MyClass__myPrivateMethod()
我已经从C#迁移了,起初它对我来说也很奇怪但是过了一段时间我才发现只有Python代码设计者对OOP的思考方式才有所不同。
Afshin Amiri answered 2019-03-27T23:44:26Z