Ответ 1
Проблема заключается в том, что, написав super(MyClass, self).__init__(text)
, вы говорите, что используется суперсоответствие по отношению к любому классу MyClass
, к которому относится в то время, когда вызывается super
. Но декоратор заменяет MyClass
подклассом самого себя. Поэтому, когда ваш оригинальный метод __init__
называется MyClass
, фактически относится к подклассу класса, который определяет исполняемый метод.
Чтобы сказать это шаг за шагом, я собираюсь назвать исходный класс (как написано в источнике) OrigMyClass
, и полученную версию (после декоратора) DecMyClass
. Я использую MyClass
как переменную, потому что ее значение изменяется во время выполнения.
-
Вы определяете метод
__init__
наOrigMyClass
, но метод__init__
вызываетsuper(MyClass, self)
, а неsuper(OrigMyClass, self)
. Таким образом, какой метод будет фактически вызван, зависит от того, к чему относитсяMyClass
во время вызова метода. ЗначениеMyClass
просматривается во время выполнения, как и любая другая переменная; размещение его внутри вызоваsuper
или внутри метода__init__
не магически привязывает его к классу, в котором он находится, когда вы его пишете; переменные в функциях оцениваются, когда они вызывается, а не когда они определены. -
Декоратор работает. Декоратор определяет новый класс
DecMyClass
как подклассOrigMyClass
.DecMyClass
определяет__init__
, который вызываетsuper(DecMyClass, self)
. -
После запуска декоратора имя
MyClass
привязано к классуDecMyClass
. Обратите внимание, что это означает, что при последующем вызовеsuper(MyClass, self)
он будет выполнятьsuper(DecMyClass, self)
. -
Когда вы выполняете
MyClass(111)
, вы создаете объектDecMyClass
.DecMyClass.__init__
вызываетsuper(DecMyClass, self).__init__
. ВыполняетсяOrigMyClass.__init__
. -
OrigMyClass.__init__
вызываетsuper(MyClass, self).__init__
. ПосколькуMyClass
относится кDecMyClass
, это то же самое, что иsuper(DecMyClass, self).__init__
. НоDecMyClass
является подклассомOrigMyClass
. Ключевым моментом является то, что, посколькуMyClass
относится кDecMyClass
,OrigMyClass
на самом деле вызывает супер в подклассе самого себя. -
Таким образом,
super(DecMyClass, self).__init__
снова вызываетOrigMyClass.__init__
, который снова вызывает себя и т.д. до бесконечности.
Эффект такой же, как и этот код, что может сделать путь выполнения более очевидным:
>>> class Super(object):
... def __init__(self):
... print "In super init"
... super(Sub, self).__init__()
>>> class Sub(Super):
... def __init__(self):
... print "In sub init"
... super(Sub, self).__init__()
Обратите внимание, что super
вызывает super(Sub, self)
. Он пытается вызвать метод суперкласса, но он пытается вызвать метод суперкласса Sub
. Суперкласс Sub
равен super
, поэтому super
завершает вызов своего собственного метода снова.
Изменить: просто для выяснения проблем, связанных с именами, которые вы подняли, вот еще несколько другой пример, который имеет тот же результат:
>>> class Super(object):
... def __init__(self):
... print "In super init"
... super(someClass, self).__init__()
>>> class Sub(Super):
... def __init__(self):
... print "In sub init"
... super(Sub, self).__init__()
>>> someClass = Sub
Это должно дать понять, что аргумент класса super
(первый аргумент здесь someClass
) не является каким-то особым. Это просто обычное имя, значение которого просматривается обычным способом в обычное время, а именно при выполнении вызова super
. Как показано в этом примере, переменная даже не должна существовать во время определения метода; значение отображается в момент вызова метода.