如何获取 magic __getattr__ 中的实例属性?
How to get instance attribute inside magic __getattr__?
在 class 中,我想将对 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
函数。
如何访问实例中的命名属性?
Python language refererence about __getattr__:
object.__getattr__(self, name)
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
Note that if the attribute is found through the normal mechanism, __getattr__() is not called. (This is an intentional asymmetry between __getattr__() and __setattr__().) This is done both for efficiency reasons and because otherwise __getattr__() would have no way to access other attributes of the instance. Note that at least for instance variables, you can fake total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the __getattribute__() method below for a way to actually get total control over attribute access.
这意味着 __getattr__
只有在没有实例变量、没有 class 属性和没有找到同名方法的情况下才会被调用。
所以您的代码适用于 "addr"。您将获得其他名称的无限递归,因为 hasattr()
also uses __getattr__
.
您应该避免在 __getattr__
中使用 hasattr()
和 getattr()
。
相反,您可以在捕获 AttributeError
.
的 try-except
块中使用 super().__getattribute__(name)
请注意,super().__getattribute__(name)
不会在父级 class 上调用 __getattr__(name)
。所以 如果 你想支持一个 class 层次结构,其中 __getattr__
可以链接到你需要的另一个 class 的 __getattr__
方法如果 super.__getattribute__()
失败,则调用 super().__getattr__(name)
。
使用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
在 class 中,我想将对 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
函数。
如何访问实例中的命名属性?
Python language refererence about __getattr__:
object.__getattr__(self, name)
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
Note that if the attribute is found through the normal mechanism, __getattr__() is not called. (This is an intentional asymmetry between __getattr__() and __setattr__().) This is done both for efficiency reasons and because otherwise __getattr__() would have no way to access other attributes of the instance. Note that at least for instance variables, you can fake total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the __getattribute__() method below for a way to actually get total control over attribute access.
这意味着 __getattr__
只有在没有实例变量、没有 class 属性和没有找到同名方法的情况下才会被调用。
所以您的代码适用于 "addr"。您将获得其他名称的无限递归,因为 hasattr()
also uses __getattr__
.
您应该避免在 __getattr__
中使用 hasattr()
和 getattr()
。
相反,您可以在捕获 AttributeError
.
try-except
块中使用 super().__getattribute__(name)
请注意,super().__getattribute__(name)
不会在父级 class 上调用 __getattr__(name)
。所以 如果 你想支持一个 class 层次结构,其中 __getattr__
可以链接到你需要的另一个 class 的 __getattr__
方法如果 super.__getattribute__()
失败,则调用 super().__getattr__(name)
。
使用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