今天写一段程序时遇到一个问题,查了好一会才搞清楚。代码可以简化为下面这个小代码:
#!/usr/bin/env python
# encoding: utf-8
def __p():
print("called")
class X:
def z(self):
__p()
X().z()
这段代码运行的时候会提示错误:
Traceback (most recent call last):
File "test.py", line 11, in <module>
X().z()
File "test.py", line 9, in z
__p()
NameError: name '_X__p' is not defined
出现这个问题的原因是, python 使用一种 name mangling 技术,将类里出现的__membername
替换成 _classname__membername
,而且不管是不是通过类或self
引用。在上面的例子中,__p
被替换成了_X__p
,从而出现找不到定义的错误。
Python 从语言角度并没有强制的私有化支持,通过这种方式来禁止直接访问。上面的 __p
只能在全局函数里使用,类的__p
也只能在本类里使用,其他类包括子类都无法直接访问。但只要知晓其规则,可以通过改名后的名字来访问:
class A():
def __init__(self):
self.__name = 'python' # 私有变量,翻译成 self._A__name = 'python'
def __say(self): # 私有方法,翻译成 def _A__say(self)
print self.__name # 翻译成 self._A__name
a = A()
print a.__name # 访问私有属性,报错 no attribute '__name'
print a.__dict__ # 查询出实例a的属性的集合
print a._A__name # 这样,就可以访问私有变量了
a.__say() # 调用私有方法,报错 no attribute '__say'
print dir(a) # 获取实例的所有属性和方法
a._A__say() # 这样,就可以调用私有方法了
但这种方法并无法让类访问一个模块全局定义的私有变量。另一方面,其它文件导入该模块(假设为test.py
)后,(不在类里)还可以直接访问test.__p
,并没有改名以及任何限制。
Q. E. D.