Вот класс 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)
, что является вызовом ... ну, вы его получите.
Это не приводит к использованию метода >
, использующего его метод. Зачем?
Что вы ожидаете от 'self.value' в' __setattr__'? Вы никогда не удаляете этот атрибут нигде, поэтому 'try..except..else' всегда переходит в' else'. –
Это не главное. он просто демонстрирует, что __setattr __() ** является ** рекурсивным, но __gt __() не является. – rbp
@MartijnPieters при инициализации экземпляра 'A' вы получите' name self.value' не определен, потому что значение не может быть установлено без первого. Удалите блок try, попробуйте напечатать назначенное значение, и вы увидите, что я имею в виду. – cat