我有两个类松散地采用以下形式:
class Foo:
def __init__(self, foo):
self.__foo = foo
class Bar(Foo):
def bar(self):
print self.__foo
当我尝试在bar
的实例上调用Bar
方法时,它会失败。
b = Bar('foobar')
b.bar()
结果:
Traceback (most recent call last):
File "foobar.py", line 14, in <module>
b.bar()
File "foobar.py", line 10, in bar
print self.__foo
AttributeError: Bar instance has no attribute '_Bar__foo'
答案 0 :(得分:4)
简单。 __foo
在开头包含2个下划线,因此它被假定为类私有方法,并且它已转换为_Classname__method
。
当您请求访问Bar
对象上名为此类的属性时,它会询问Bar
类是否有此方法(不是Foo
类),因此self.__foo
是始终与self._Bar__foo
相同。
当开始在类定义中以文本形式出现的标识符时 带有两个或多个下划线字符,并且不以两个或更多个结尾 下划线,它被认为是该类的私人名称。私人的 在为代码生成之前,名称将转换为更长的形式 他们。转换插入带有前导的类名 删除了下划线,并在前面插入了一个下划线 名称。例如,标识符__spam发生在名为的类中 火腿将变成_Ham__spam。
如果您稍微修改代码
class Foo:
def __init__(self, foo):
self.__foo = foo
assert hasattr(self, '_Foo__foo'), 'Attribute has been just created'
class Bar(Foo):
def bar(self):
assert hasattr(self, '_Foo__foo'), 'No errors, thanks to inheritance'
assert
语句不会导致任何AssertionError
。
将__getattribute__
方法添加到Bar
类以捕获对Bar
个对象的所有请求:
class Bar(Foo):
def bar(self):
print('Accessing __foo from bar')
print(self.__foo)
def __getattribute__(self, name):
print('Requested', name)
return super().__getattribute__(name)
b = Bar('foobar')
b.bar()
输出中将有3行(除了AttributeError
):
Requested bar
Accessing __foo from bar
Requested _Bar__foo # AttributeError follows
正如您所看到的,如果您要求的属性有2个前导下划线,则Python会动态重命名。