如何在magic __getattr__中获取实例属性?

时间:2017-02-06 10:15:46

标签: python python-3.x getattr

在课程中,我想通过调用inst.addr将调用映射到inst.addr_fun(),从而创建此代码:

class Common:
    ...
    def __getattr__(self, name):
        if hasattr(self, '{}_fun'.format(name)):
            return getattr(self, '{}_fun'.format(name))()
        else:  
            raise AttributeError('attribute unknown in instance')
    def addr_fun(self):
        return 42

然而,由于getattr调用了__getattr__,因此导致递归,因此我无法访问addr_fun函数。

如何访问实例中的命名属性?

2 个答案:

答案 0 :(得分:4)

Python language refererence about __getattr__

  

object .__ getattr __(self,name)

     

当属性查找未在通常位置找到属性时调用(即,它不是实例属性,也不是在类树中找到自己)。 name是属性名称。此方法应返回(计算的)属性值或引发AttributeError异常。

     

请注意,如果通过常规机制找到属性,则不会调用__getattr __()。 (这是__getattr __()和__setattr __()之间的故意不对称。)这是出于效率原因而做的,因为否则__getattr __()将无法访问实例的其他属性。请注意,至少对于实例变量,您可以通过不在实例属性字典中插入任何值来伪造总控制(而是将它们插入另一个对象中)。请参阅下面的__getattribute __()方法,以获得实际获得对属性访问的完全控制的方法。

这意味着只有在没有找到实例变量,没有类属性和没有找到同名方法的情况下才会调用__getattr__

所以你的代码适用于“addr”。您将获得其他名称的无限递归,因为hasattr() also uses __getattr__

您应避免在hasattr()内使用getattr()__getattr__。 相反,您可以在捕获super().__getattribute__(name)的{​​{1}}块中使用try-except

请注意,AttributeError不会在父类上调用super().__getattribute__(name)。所以 if 你想要支持一个类层次结构,其中__getattr__(name)可能链接到另一个类的__getattr__方法,如果{{1}需要调用__getattr__失败了。

答案 1 :(得分:1)

使用object.__getattribute__。例如:

class C:
    x = 10

    def __getattribute__(self, name):
        try:
            return super().__getattribute__('{}_fun'.format(name))
        except AttributeError:
            return super().__getattribute__(name)

    def a_fun(self):
        print('Calling a_fun(), value of x is {}'.format(self.x))


c = C()
c.a()
>>> Calling a_fun(), value of x is 10