引言
Python不像C++、Java、C#等有明确的公共、私有或受保护的关键字来定义成员函数或属性,它使用约定的单下划线“_”和”__”双下划线作为函数或属性的前缀来标识。使用单下划线还是双下划线,是有很大的区别的。
1. 单下划线的函数或属性,在类定义中可以调用和访问,类的实例可以直接访问,子类中可以访问;
2. 双下划线的函数或属性,在类定义中可以调用和访问,类的实例不可以直接访问,子类不可访问。
注意:对于双下划线的函数或属性,Python解释器使用了名字混淆的方法, 将私有的方法”__method”变成了”_classname__method”了,具体看下文示例。
双下划线的私有函数和属性,在子类中不可见,不存在”覆盖“
-
class Base(object):
-
def __private(self):
-
print(
"private value in Base")
-
-
def _protected(self):
-
print(
"protected value in Base")
-
-
def public(self):
-
print(
"public value in Base")
-
self.__private()
-
self._protected()
-
-
class Derived(Base):
-
def __private(self):
-
print(
"override private")
-
-
def _protected(self):
-
print(
"override protected")
-
-
-
print dir(Base)
-
print(
"="*
80)
-
d = Derived()
-
d.public()
-
d._protected()
-
d._Derived__private()
-
print(
"="*
80)
-
d.__private()
输出结果如下:
-
>>>
-
[
'_Base__private',
'__class__',
'__delattr__',
'__dict__',
'__doc__',
'__format__',
'__getattribute__',
'__hash__',
'__init__',
'__module__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'_protected',
'public']
-
================================================================================
-
<span style=
"color:#FF0000;">
public value
in Base
-
private value
in Base
-
override
protected</span>
-
override
protected
-
<span style=
"color:#FF0000;">
override
private</span>
-
================================================================================
-
-
Traceback (most recent call last):
-
File
"D:\temp\test.py", line
91,
in <module>
-
d.__private()
-
AttributeError:
'Derived'
object has no attribute
'__private'
-
>>>
注意上面输出的红色字体部分,与我们想象中的输出可能不太一样啊。调用子类的public方法时,子类的双下划线方法 __private 并没有”覆盖“父类的方法,但子类的单下划线方法_protected方法却”覆盖“了父类的方法。
这其中的原因,就在于子类要”覆盖“父类的方法,得让子类能够具有访问父类相应方法的权限才行。
不要定义Python的混淆类方法名称
Python解释器对于类(ClassName)双下划线的私有方法(__method),会进行名称混淆(Name Mangle),规则为 _ClassName__method。所以不要在类方法中同时存在__method和 _ClassName__method。
示例
-
class Base(object):
-
def _secret(self):
-
print(
"Base secret")
-
-
def __hide(self):
-
print(
"Normal __hide")
-
-
def _Base__hide(self):
-
print(
"Special _Base__hide")
-
-
def public(self):
-
print(
"From public method")
-
self.__hide()
-
-
print dir(Base())
-
print(
"="*
80)
-
Base().public()
输出如下
-
[
<span style="color:#FF0000;">'_Base__hide'</span>,
'class',
'delattr',
'dict',
'doc',
'format',
'getattribute',
'hash',
'init',
'module',
'new',
'reduce',
'reduce_ex',
'repr',
'setattr',
'sizeof',
'str',
'subclasshook',
'weakref',
'_secret',
'public']
-
================================================================================
-
From public method
-
<span style=
"color:#FF0000;">Special _Base__hide<
/span>
可以看出 __hide 已经被 _Base__hide方法替换掉了。外部也可以直接通过 Base()._Base__hide()方式调用(但千万别用这种方式实现,比较混乱!)。