2016-01-15 5 views
0

Вот класс Python, который реализует некоторые magic methods:Почему эти магические методы не рекурсивные?

class A(): 
    def __init__(self, value): 
     self.value = value 

    def inc(self): 
     self.value += 1 
     return self.value 

    def dec(self): 
     self.value -= 1 
     return self.value 

    def __eq__(self, other): 
     return self.value == other 

    def __gt__(self, other): 
     return self.value > other 

    def __lt__(self, other): 
     return self.value < other 

    def __setattr__(self, name, value): 
     try: 
      self.value 
     except: 
      pass 
     else: 
      print(name, "changed its value from", self.value, "to", value) 
     finally: 
      super().__setattr__(name, value) 

Он реализует (хотя и резервные) методы, определенных на некоторых объектах, и позволяет сравнивать и (в __setattr__ случае) подсекать назначение:

>>> a.inc() 
value changed its value from 0 to 1 
1 

Предположим, что мы заново __setattr__, чтобы сделать его проще:

def __setattr__(self, name, value): 
    self.__setattr__(name, value) 

Теперь попробуйте ING назначить self.value получит вам пощечину:

File "<pyshell#50>", line 17, in __setattr__ 
    self.__setattr__(name, value) 
    File "<pyshell#50>", line 17, in __setattr__ 
    self.__setattr__(name, value) 
    File "<pyshell#50>", line 17, in __setattr__ 
    self.__setattr__(name, value) 
    File "<pyshell#50>", line 17, in __setattr__ 
    self.__setattr__(name, value) 
    File "<pyshell#50>", line 17, in __setattr__ 
    self.__setattr__(name, value) 
RecursionError: maximum recursion depth exceeded 

Ну, это было ожидаемо. Функция __setattr__ рекурсивна; поэтому нам нужно использовать super().

Вопрос в том, почему эта рекурсия не применяется к другим магическим методам; то есть, когда я звоню obj.__gt__(otherval), это то же самое, что и obj > otherval, что является вызовом obj.__gt__(otherval), что является вызовом ... ну, вы его получите.

Это не приводит к использованию метода >, использующего его метод. Зачем?

+0

Что вы ожидаете от 'self.value' в' __setattr__'? Вы никогда не удаляете этот атрибут нигде, поэтому 'try..except..else' всегда переходит в' else'. –

+0

Это не главное. он просто демонстрирует, что __setattr __() ** является ** рекурсивным, но __gt __() не является. – rbp

+0

@MartijnPieters при инициализации экземпляра 'A' ​​вы получите' name self.value' не определен, потому что значение не может быть установлено без первого. Удалите блок try, попробуйте напечатать назначенное значение, и вы увидите, что я имею в виду. – cat

ответ

4

Вы не вызываете > на self. Вы вызываете его на self.value, который представляет собой целочисленное значение (например, совершенно другого типа).

Если вы использовали:

def __gt__(self, other): 
    return self > other 

вы бы в конечном итоге в бесконечном цикле тоже.

Смежные вопросы