Перезапись __getattr__ вызывает рекурсию
Я пытаюсь создать класс-оболочку, а затем перезаписать __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
печатается много раз. Возможно ли то, что я хочу?
2 ответа
Это
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
NB: я полагаю, вы сделали foo
вычисляемый атрибут для ленивой инициализации _foo
иначе это имеет мало смысла. Если это так, вы также можете, довольно просто, создать _foo
в инициализаторе со значением часового (обычно None
если None
является допустимым значением для этого атрибута) и дать ему реальное значение в foo()
,
Вам нужно установить _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