我正在尝试创建一个包装器类,然后覆盖__getattr__
,以便将不在包装器类中的对属性的请求传递到内部对象中。下面是一个玩具示例,其中我使用列表作为内部对象-
class A(object):
def __init__(self):
pass
def __getattr__(self, name):
print 'HERE'
return getattr(self.foo, name)
@property
def foo(self):
try:
return self._foo
except:
self._foo = [2, 1]
return self._foo
我想做类似的事情
a = A()
a.sort() # initializes and sorts _foo
print a.foo
显示[1, 2]
最后,当首次调用_foo
或某人试图从foo
中获得一个不在A()
中的属性时,我需要A
进行初始化。不幸的是,我遇到了某种递归,HERE
被多次打印。我想要什么?
答案 0 :(得分:1)
此
return getattr(self.foo, name)
实际上是:
foo = self.foo
return getattr(foo, name)
现在self.foo
实际上是这样称呼的:
try:
return self._foo
,由于您的类定义了__getattr__
,并且-至少有一个对self.foo
的首次调用-没有_foo
属性,因此调用self.__getattr__("_foo")
, self.foo
,等等等等……
简单的解决方案:确保self._foo
之前(即在初始化程序中)定义,而不是尝试在foo()
中定义。
您还可以测试实例的字典中是否存在_foo
,但是如果_foo
也是计算属性,也会破坏继承-是否存在问题取决于上下文和具体的用例。
@property
def foo(self):
if '_foo' not in self.__dict__:
self._foo = [2, 1]
return self._foo
注意:我假设您将foo
设为计算属性,以允许_foo
的延迟初始化,否则就没有意义了。如果是这种情况,您还可以非常简单地在初始化器中创建一个带有前哨值的_foo
(通常为None
,除非None
是此属性的有效值)并提供它在foo()
中是真正的价值。
答案 1 :(得分:1)
您最初需要将_foo
设置为某种值,即使它不是真正的值。像这样:
class A(object):
_foo = None
def __init__(self):
pass
def __getattr__(self, name):
print 'HERE'
return getattr(self.foo, name)
@property
def foo(self):
if self._foo is None:
self._foo = [2, 1]
return self._foo