首先,不同于其他编程语言,Python中不存在真正意义上的“私有方法/属性”,Python中所胃的“私有方法”要么基于约定,要么基于编译期的改写(Name Mangling)。与私有方法、私有属性密切相关的是单下划线、双下划线。下面详细解释一下:
_*以前置单下划线开始的方法名或属性名,这仅仅是一种形式上约定的私有方法或属性,在语法上无人任何约束性,人们仅仅是通过这种命名规范告知读者:这个方法或属性在定位上是私有的,不应在对像以外的地方使用。所以实际上,如果你想,还是可以在对像以外的地方调用或读写它们。以下是一段测试代码,用于验证该类方法或属性的可见性:
class A(object):def __init__(self):self._private=0def _private_method(self):print('AAAAA')
>>>a=A()
>>>a._private #可直接访问
0
>>>a._private_method() #可直接访问
AAAAA
__*以前置双下划线开始的方法名或属性名,仍旧是用于标识私有方法或属性的,但较之于_*有了一些“实质性的”变化,那就是你确实无法“直接”在对像以外的地方调用或读写它们了,这是因为:Python使用了Name Mangling技术,在编译时将__membername改写成了 _classname__membername,即:以双下划线开始的方法或属性都被"转义"成为单下划线+类名+双下划线+成员名的形式。所以,在知晓了转换规则后,你依然可以在对象外部以转义后的名称调用或读写它们。以下是一段测试代码,用于验证该类方法或属性的可见性:
class A(object):def __init__(self):self.__private=0def __private_method(self):print('AAAAA')
>>>a=A()
>>>a.__private # 直接调用,不可见
Traceback (most recent call last):File "", line 1, in
AttributeError: 'A' object has no attribute '__private'
>>>a.__private_method() # 直接调用,不可见
Traceback (most recent call last):File "", line 1, in
AttributeError: 'A' object has no attribute '__private_method'
>>>a._A__private # 改为编译器改写后的真实属性名后,可见
0
>>>a._A__private_method() # 改为编译器改写后的真实方法名后,可见
AAAAA
不过,在《Fluent Python》一书中,作者引用Ian Bicking 的一句话用于表达对__*即Name Mangling的态度:
绝对不要使用两个前导下划线,这是很烦人的自私行为。如果担心名称冲突,应该明确使用一种名称改写方式(如
_MyThing_blahblah)。这其实与使用双下划线一样,不过自己定的规则比双下划线易于理解。
即:慎用最好不用__*形式的私有方法或属性,这不是个好习惯。
__*__以前置双下划线开始,后置双下划线结束的方法名,这已经和私有方法或属性无关了,这是Python语言系统定义的一些特殊函数,称之为:魔法函数 / Magic Methods / Dunder Methods, 我们将在另外一篇文章中单独介绍。
参考:
https://blog.csdn.net/sxingming/article/details/52875125
https://segmentfault.com/a/1190000040064040