在课程中,我想通过调用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
函数。
如何访问实例中的命名属性?
答案 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