问题:为什么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()
我在那里所做的是创建一个具有公共方法和私有方法的类,并将其实例化。
接下来,我将其称为public方法。
>>> 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不支持封装,那么为什么还要尝试呢?是什么赋予了?
回答 0
名称加扰用于确保子类不会意外覆盖其超类的私有方法和属性。它并非旨在防止从外部故意访问。
例如:
>>> 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}
当然,如果两个不同的类具有相同的名称,它就会崩溃。
回答 1
私有功能的例子
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 ###
回答 2
当我第一次从Java到Python时,我讨厌这一点。吓死我了。
今天,它可能只是我最喜欢Python 的一件事。
我喜欢在一个平台上,人们可以互相信任,而不必觉得自己需要围绕其代码构建坚不可摧的墙。在高度封装的语言中,如果API有错误,并且您已找出问题所在,则可能仍无法解决它,因为所需的方法是私有的。在Python中,态度是:“确定”。如果您认为自己了解这种情况,也许您甚至已经读过它,那么我们只能说“祝您好运!”。
请记住,封装与“安全性”或使孩子远离草坪之间的关系不大。这只是使代码库更易于理解的另一种模式。
回答 3
来自http://www.faqs.org/docs/diveintopython/fileinfo_private.html
严格来说,私有方法可以在其类之外访问,只是不容易访问。Python中没有什么是真正私有的。在内部,私有方法和属性的名称会被随意修改和修改,以使它们的名称看起来不可访问。您可以通过名称_MP3FileInfo__parse访问MP3FileInfo类的__parse方法。承认这很有趣,然后保证永远不要在真实代码中做到这一点。出于某种原因,私有方法是私有的,但是与Python中的许多其他事物一样,私有方法最终是约定俗成的问题,而不是强制性的问题。
回答 4
常用的短语是“我们在这里都是成年人”。通过在单个下划线(不要暴露)或双下划线(隐藏)前面加上,可以告诉Class用户您希望该成员以某种方式成为“私有”成员。但是,除非其他人有充分的理由不这样做(例如,调试器,代码完成),否则您将信任其他所有人的行为负责并尊重。
如果您确实必须拥有私有的内容,则可以在扩展中实现它(例如,在C for CPython中)。但是,在大多数情况下,您只是学习Python的做事方式。
回答 5
并不是说您绝对不能绕开任何语言的成员私有性(C ++中的指针算术,.NET / Java中的反射)。
关键是,如果您尝试偶然调用私有方法,则会出错。但是,如果您想用脚射击自己,那就继续吧。
编辑:您不会尝试通过OO封装来保护您的东西,是吗?
回答 6
该class.__stuff
命名约定可以让程序员知道他是不是要访问__stuff
外部。改名这个名字使任何人都不太可能偶然地这样做。
没错,您仍然可以解决此问题,它甚至比其他语言还容易(顺便说一句,BTW也允许您这样做),但是如果Python程序员关心封装,那么他将不会这样做。
回答 7
当模块属性名称以单个下划线(例如_foo)开头时,存在类似的行为。
使用该from*
方法时,这样命名的模块属性将不会复制到导入模块中,例如:
from bar import *
但是,这是约定,不是语言限制。这些不是私有属性。它们可以被任何进口商引用和操纵。有人认为,因此,Python无法实现真正的封装。
回答 8
这只是这些语言设计选择之一。在某种程度上,它们是合理的。他们做到了,所以您需要走很长的路才能尝试调用该方法,如果真的很需要它,则必须有充分的理由!
我想到了调试挂钩和测试作为可能的应用程序,它们当然是负责任地使用的。
回答 9
在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
请注意,修改规则主要是为了避免发生意外。仍然可以访问或修改被视为私有的变量。这在特殊情况下(例如在调试器中)甚至很有用。
即使问题很旧,我也希望我的摘录对您有所帮助。
回答 10
关于私有方法和属性的最重要的考虑是告诉开发人员不要在类之外调用它,这就是封装。人们可能会误解封装的安全性。当一个人故意使用您提到的那种语法时,您就不需要封装。
obj._MyClass__myPrivateMethod()
我已经从C#迁移了,起初对我来说也很奇怪,但是过了一会儿我才想到,只有Python代码设计人员对OOP的思考方式有所不同。
回答 11
为什么Python的“私有”方法实际上不是私有的?
据我了解,它们不能是私有的。如何保护隐私?
显而易见的答案是“只能通过访问私有成员self
”,但这是行不通的- self
在Python中并不特殊,它不过是函数第一个参数的常用名称。