Trouple访问python超类属性

时间:2014-05-07 15:10:47

标签: python inheritance

我有两个类松散地采用以下形式:

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'

我的理解是,此代码应该基于two other个问题,为什么不这样做?

1 个答案:

答案 0 :(得分:4)

简单。 __foo在开头包含2个下划线,因此它被假定为类私有方法,并且它已转换为_Classname__method

当您请求访问Bar对象上名为此类的属性时,它会询问Bar类是否有此方法(不是Foo类),因此self.__foo是始终与self._Bar__foo相同。

来自documentation

  

当开始在类定义中以文本形式出现的标识符时   带有两个或多个下划线字符,并且不以两个或更多个结尾   下划线,它被认为是该类的私人名称。私人的   在为代码生成之前,名称将转换为更长的形式   他们。转换插入带有前导的类名   删除了下划线,并在前面插入了一个下划线   名称。例如,标识符__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会动态重命名。