Объект 'super' не вызывает __getattr__
У меня есть один объект, завернутый в другой. "Обертка" получает доступ к атрибутам объекта "Обернутый" путем переопределения __getattr__
, Это работает хорошо, пока мне не нужно переопределить атрибут в подклассе, а затем получить доступ к атрибуту из базового класса, используя super()
,
Я все еще могу получить доступ к атрибуту непосредственно из __getattr__
но почему super()
не работа?
class Wrapped(object):
def __init__(self, value):
self.value = value
def hello_world(self):
print 'hello world', self.value
class Wrapper(object):
def __init__(self, obj):
self.wrapped_obj = obj
def __getattr__(self, name):
if name in self.__dict__:
return getattr(self, name)
else:
return getattr(self.wrapped_obj, name)
class Subclass(Wrapper):
def __init__(self, obj):
super(Subclass, self).__init__(obj)
def hello_world(self):
# this works
func = super(Subclass, self).__getattr__('hello_world')()
# this doesn't
super(Subclass, self).hello_world()
a = Wrapped(2)
b = Subclass(a)
b.hello_world()
1 ответ
В соответствии с этим, super не допускает неявные вызовы таких функций, как __getattr__
, Я не уверен, почему это реализовано таким образом (вероятно, есть веская причина, и все уже достаточно запутанно, поскольку супер-объект имеет __getattribute__
а также __get__
методы, как есть), но кажется, что все так, как есть.
Изменить: Этот пост, кажется, прояснить ситуацию немного. Похоже, что проблема заключается в дополнительном слое косвенного __getattribute__
игнорируется при неявном вызове функций. дела foo.x
эквивалентно
foo.__getattr__(x)
(Предполагая, что нет __getattribute__
Метод определен, а х не в foo.__dict__
) Однако это НЕ эквивалентно
foo.__getattribute__('__getattr__')(x)
Поскольку super возвращает прокси-объект, у него есть дополнительный уровень косвенности, который приводит к ошибкам.
PS The self.__dict__
проверьте в вашем __getattr__
Функция совершенно не нужна. __getattr__
вызывается, только если атрибут не существует в вашем файле. (Использование __getattribute__
если вы хотите, чтобы он всегда вызывался, но тогда вы должны быть очень осторожны, потому что даже что-то простое, как if name in self.__dict__
вызовет бесконечную рекурсию.