Иногда тексты должны быть прочитаны больше для вкуса идеи, а не для деталей. Это один из таких случаев.
На связанной странице в примерах 2.5, 2.6 и 2.7 все должны использовать один метод, do_your_stuff
. (То есть do_something
следует изменить на do_your_stuff
.)
Кроме того, как указал Нед Дейли , A.do_your_stuff
должен быть методом класса.
class A(object):
@classmethod
def do_your_stuff(cls):
print 'This is A'
class B(A):
@classmethod
def do_your_stuff(cls):
super(B, cls).do_your_stuff()
B.do_your_stuff()
super(B, cls).do_your_stuff
возвращает связанный метод (см. сноска 2 ). Поскольку cls
был передан в качестве второго аргумента super()
, именно cls
привязывается к возвращаемому методу. Другими словами, cls
передается в качестве первого аргумента методу do_your_stuff()
класса A.
Повторим: super(B, cls).do_your_stuff()
вызывает A
метод do_your_stuff
вызывается с cls
переданным в качестве первого аргумента. Для того, чтобы это сработало, A
do_your_stuff
должен быть методом класса. Связанная страница не упоминает об этом,
но это определенно так.
PS. do_something = classmethod(do_something)
- это старый способ создания метода класса.
Новый (er) способ - использовать декоратор @classmethod.
Обратите внимание, что super(B, cls)
нельзя заменить на super(cls, cls)
. Это может привести к бесконечным циклам. Например,
class A(object):
@classmethod
def do_your_stuff(cls):
print('This is A')
class B(A):
@classmethod
def do_your_stuff(cls):
print('This is B')
# super(B, cls).do_your_stuff() # CORRECT
super(cls, cls).do_your_stuff() # WRONG
class C(B):
@classmethod
def do_your_stuff(cls):
print('This is C')
# super(C, cls).do_your_stuff() # CORRECT
super(cls, cls).do_your_stuff() # WRONG
C.do_your_stuff()
повысит RuntimeError: maximum recursion depth exceeded while calling a Python object
.
Если cls
равно C
, то super(cls, cls)
ищет C.mro()
класс, следующий за C
.
In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]
Поскольку этот класс равен B
, когда cls
равен C
, super(cls, cls).do_your_stuff()
всегда вызывает B.do_your_stuff
. Поскольку super(cls, cls).do_your_stuff()
вызывается внутри B.do_your_stuff
, вы в конечном итоге вызываете B.do_your_stuff
в бесконечном цикле.
В Python3 была добавлена форма 0-аргумента super
, чтобы super(B, cls)
можно было заменить на super()
, и Python3 выяснит из контекста, что super()
в определении class B
должно быть эквивалентно super(B, cls)
.
Но ни при каких обстоятельствах super(cls, cls)
(или по аналогичным причинам super(type(self), self)
) никогда не бывает правильным.