Использование super с методом класса
-
08-07-2019 - |
Вопрос
Я пытаюсь изучить функцию super () в Python.
Я думал, что понял это, пока не наткнулся на этот пример (2.6) и не обнаружил, что застрял.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "test.py", line 9, in do_something
do_something = classmethod(do_something)
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)
>>>
Это было не то, чего я ожидал, когда читал эту строку прямо перед примером:
Если мы используем метод класса, у нас нет экземпляра для вызова super .К счастью для нас, super работает даже с типом в качестве второго аргумента.--- Тип может быть передан непосредственно super, как показано ниже.
Это именно то, что Python говорит мне, что это невозможно, говоря, что do_something() должен вызываться с экземпляром B.
Решение
Иногда тексты приходится читать больше для того, чтобы уловить суть идеи, а не для того, чтобы вникнуть в детали.Это один из таких случаев.
В связанная страница, Все примеры 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()
из класса А.
Чтобы повторить: super(B, cls).do_your_stuff()
причины A
's do_your_stuff
метод, который должен быть
вызван с помощью cls
передается в качестве первого аргумента.Для того, чтобы это сработало, A
's
do_your_stuff
должен быть метод класса.Связанная страница не упоминает об этом,
но это определенно так.
PS. do_something = classmethod(do_something)
это старый способ создания classmethod.Новый (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)
) всегда корректен.
Другие советы
В Python 3 вы можете пропустить указание аргументов для super
,
class A:
@classmethod
def f(cls):
return "A's f was called."
class B(A):
@classmethod
def f(cls):
return super().f()
assert B.f() == "A's f was called."
Я обновил статью, чтобы она стала немного понятнее: Атрибуты и методы Python # Super
В приведенном выше примере использования метода класса показано, что такое метод класса - он передает сам класс вместо экземпляра в качестве первого параметра. Но вам даже не нужен экземпляр для вызова метода, например:
>>> class A(object):
... @classmethod
... def foo(cls):
... print cls
...
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>
Пример с веб-страницы выглядит опубликованным. Вы создали метод do_something
для суперкласса, но не превратили его в метод класса? Что-то вроде этого даст вам эту ошибку:
>>> class A(object):
... def do_something(cls):
... print cls
... # do_something = classmethod(do_something)
...
>>> class B(A):
... def do_something(cls):
... super(B, cls).do_something()
... do_something = classmethod(do_something)
...
>>> B().do_something()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in do_something
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)
Думаю, теперь я понял суть дела благодаря этому красивому сайту и прекрасному сообществу.
Если вы не возражаете, пожалуйста, исправьте меня, если я ошибаюсь в методах обучения (что я сейчас пытаюсь полностью понять):
# EXAMPLE #1
>>> class A(object):
... def foo(cls):
... print cls
... foo = classmethod(foo)
...
>>> a = A()
>>> a.foo()
# THIS IS THE CLASS ITSELF (__class__)
class '__main__.A'
# EXAMPLE #2
# SAME AS ABOVE (With new @decorator)
>>> class A(object):
... @classmethod
... def foo(cls):
... print cls
...
>>> a = A()
>>> a.foo()
class '__main__.A'
# EXAMPLE #3
>>> class B(object):
... def foo(self):
... print self
...
>>> b = B()
>>> b.foo()
# THIS IS THE INSTANCE WITH ADDRESS (self)
__main__.B object at 0xb747a8ec
>>>
Я надеюсь, что эта иллюстрация показывает ..