2015-11-18 4 views
2

Я сейчас работаю над проектом, который занимается функциями в абстрактном математическом смысле. Без скучных читателя с подробностями, скажу, что я имел следующую структуру в более ранней версии:Переопределение метода __getattr__ для одного экземпляра класса?

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 и друзей, чтобы назвать их как функции для обработки этого специального случая?

+1

См. Ссылку в другом комментарии - причина, по которой вы не можете ее переопределить, потому что '__getattr__' является специальным методом –

+0

Также' __getattr__' вызывается только для * отсутствующих * атрибутов, то есть тех, которые не найдены обычным способом , Если вы хотите перехватить доступ к * всем * атрибутам, реализуйте '__getattribute__'. – jonrsharpe

+0

Я не был полностью осведомлен об этой тонкости со специальными методами, и, похоже, проблема здесь. В ответ на ваш комментарий, jonrsharpe, я также попытался перезаписать '__getattribute__' (хотя я забыл упомянуть об этом, мой плохой), безрезультатно. Кроме того, если это за отсутствующие аргументы, почему это работает в ситуации на основе классов? В 'init' я устанавливаю' sub_unit = None'. –

ответ

0

Когда вы просматриваете атрибут a с foo.a, python просматривает его в словаре свойств экземпляра. Когда он не будет найден, тогда будет вызван метод __getattr__.

Наоборот, если в данном случае существует a, __getattr__ не будет называться.