我现在正在处理一项涉及抽象数学函数的项目。不想让读者感到无聊,我只说之前版本中存在以下结构:
class Foo(Bar):
def __init__(self, a, b):
self.a = a
self.b = b
self.sub_unit = Foo(a, not b)
当然,我对
Foo
的参数所做的更改并不完全是这样,但必须保证如果重复访问此属性,则会产生无限长的Foo
对象链。显然,当实例化Foo
时,这将导致无限递归。我通过删除init
的最后一行并向Foo
类添加以下内容来解决早期版本中的问题:def __getattr__(self, attr: str):
if attr == 'sub_unit':
return Foo(self.a, not self.b)
else:
return super().__getattr__(attr)
这种方法还是很不错的,因为我可以根据需要计算链条中的下一个对象。
然而,在检查代码时,我意识到出于其他原因,我需要一个Bar
的实例,而不是它的子类。为了看看是否可以覆盖单个实例的getattr
,我尝试了以下操作:
>>> foo = Bar(a=1, b=2) # sub_unit doesn't get set here.
>>> foo.__getattr__ = lambda attr: 'foo'
>>> foo.a
1
>>> foo.__getattr__('a')
'foo'
这里发生了什么我不理解的事情?为什么
foo.a
没有调用foo.__getattr__('a')
?有没有一种好的方法可以覆盖单个实例的
__getattr__
,或者我的最佳选择是重新设计所有读取sub_unit
及其相关内容的代码来将其作为函数调用,以处理这种特殊情况?
__getattr__
是一个特殊方法。 - Harry Harrison__getattr__
仅在缺失的属性上调用,即那些无法通过正常方式找到的属性。如果您想拦截对所有属性的访问,请实现__getattribute__
。 - jonrsharpe__getattribute__
(虽然我忘了提到,我的错),但没有效果。另外,如果是因为缺少参数,为什么在基于类的情况下可以工作?在init
中,我将sub_unit
设置为None
。 - David Leggsub_unit
成为一个property
,当访问时返回return Foo(self.a, not self.b)
。 - Dan D.