为什么 Python 的“私有”方法实际上并不是私有的?
-
09-06-2019 - |
题
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'
这里一切看起来都很好;我们无法调用它。事实上,它是“私人的”。嗯,实际上并非如此。跑步 目录() 对象上的 揭示了 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中的许多其他事物一样,他们的私有性最终是惯例问题,而不是武力。
常用的短语是“我们都是同意的成年人”。通过在前面添加一个单下划线(不公开)或双下划线(隐藏),您可以告诉类的用户您希望该成员以某种方式成为“私有”。但是,您相信其他人都会负责任地行事并尊重这一点,除非他们有令人信服的理由不这样做(例如调试器、代码完成)。
如果您确实必须拥有私有的东西,那么您可以在扩展中实现它(例如在 C 语言中用于 CPython)。然而,在大多数情况下,您只需学习 Pythonic 的做事方式即可。
这并不是说你绝对不能绕过任何语言中成员的私有性(C++ 中的指针算术,.NET/Java 中的反射)。
关键是,如果您尝试意外调用私有方法,则会出现错误。但如果你想搬起石头砸自己的脚,那就去做吧。
编辑:您不会尝试通过 OO 封装来保护您的东西,是吗?
这 class.__stuff
命名约定让程序员知道他不打算访问 __stuff
从外面。名称修改使得任何人都不可能意外地这样做。
确实,你仍然可以解决这个问题,它甚至比其他语言更容易(顺便说一句,也让你这样做),但如果 Python 程序员关心封装,他就不会这样做。
当模块属性名称以单个下划线开头时(例如_foo)。
使用时,这样命名的模块属性不会被复制到导入模块中 from*
方法,例如:
from bar import *
然而,这是一种约定,而不是语言限制。这些不是私有属性;它们可以被任何进口商引用和操作。有人认为,正因为如此,Python 无法实现真正的封装。
这只是这些语言设计选择之一。在某种程度上,他们是有道理的。他们这样做是为了让你需要不遗余力地尝试调用该方法,如果你真的那么需要它,你必须有一个很好的理由!
调试挂钩和测试作为可能的应用程序浮现在脑海中,当然要负责任地使用。
对于 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
请注意,损坏规则主要是为了避免事故而设计的; 仍然可以访问或修改被视为私有的变量。 这甚至在特殊情况下很有用,例如在调试器中。
即使问题很老,我也希望我的代码片段能有所帮助。
关于私有方法和属性最重要的关注点是告诉开发人员不要在类之外调用它,这就是封装。人们可能会误解封装的安全性。当一个人故意使用像你提到的那样的语法(如下)时,你不需要封装。
obj._MyClass__myPrivateMethod()
我已经从 C# 迁移过来,一开始这对我来说也很奇怪,但过了一段时间我就意识到,只有 Python 代码设计者看待 OOP 的方式有所不同。
为什么 Python 的“私有”方法实际上并不是私有的?
据我了解,他们 不能 保密。如何保护隐私?
显而易见的答案是“私人成员只能通过 self
“,但这行不通—— self
在Python中并不特殊,它无非是函数第一个参数的常用名称。