Как я могу использовать super() с одним аргументом в Python

Читая о super() Объект в Python, я прочитал следующее утверждение:

Если второй аргумент опущен, суперобъект возвращается

Что это значит и как мне использовать super() с одним аргументом в коде?

2 ответа

Функциональные объекты Python являются дескрипторами, а Python использует протокол дескриптора для привязки функций к экземпляру. Этот процесс производит связанный метод.

Связывание - это то, что делает "магию" self аргумент появляется при вызове метода, и что делает property Объект автоматически вызывает методы, когда вы пытаетесь использовать свойство как атрибут в экземплярах.

super() с двумя аргументами вызывает тот же протокол дескриптора, когда вы пытаетесь использовать его для поиска методов в родительских классах; super(Foo, self).bar() будет пересекать Foo родительские классы до атрибута bar найден, и если это объект, который является дескриптором, он будет связан с self, призвание bar затем вызывает связанный метод, который в свою очередь вызывает функцию, передающую в self аргумент как bar(self),

Для этого super() объект хранит как класс (первый аргумент) self аргумент, чтобы связать, и тип self объект как атрибуты:

>>> class Foo(object):
...     def bar(self):
...         return 'bar on Foo'
... 
>>> class Spam(Foo):
...     def bar(self):
...         return 'bar on Spam'
... 
>>> spam = Spam()
>>> super(Spam, spam)
<super: <class 'Spam'>, <Spam object>>
>>> super(Spam, spam).__thisclass__
<class '__main__.Spam'>
>>> super(Spam, spam).__self_class__
<class '__main__.Spam'>
>>> super(Spam, spam).__self__
<__main__.Spam object at 0x107195c10>

При поиске атрибутов, __mro__ атрибут __self_class__ Атрибут ищется, начиная с одной позиции после позиции __thisclass__ и результаты связаны.

super() только с одним аргументом будет пропустить __self_class__ а также __self__ атрибуты, и пока не может выполнять поиск:

>>> super(Spam)
<super: <class 'Spam'>, NULL>
>>> super(Spam).__self_class__ is None
True
>>> super(Spam).__self__ is None
True
>>> super(Spam).bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'super' object has no attribute 'bar'

Объект поддерживает протокол дескриптора, поэтому вы можете связать его так же, как вы можете связать метод:

>>> super(Spam).__get__(spam, Spam)
<super: <class 'Spam'>, <Spam object>>
>>> super(Spam).__get__(spam, Spam).bar()
'bar on Foo'

Это означает, что вы можете хранить такой объект в классе и использовать его для перехода к родительским методам:

>>> class Eggs(Spam):
...     pass
... 
>>> Eggs.parent = super(Eggs)
>>> eggs = Eggs()
>>> eggs.parent
<super: <class 'Eggs'>, <Eggs object>>
>>> eggs.parent.bar()
'bar on Spam'

Кроме того, вы также можете сделать это:

      >>> class Eggs(Spam):
...     grand_parent = super(Spam)
... 
>>> eggs = Eggs()
>>> eggs.grand_parent.bar()
'bar on Foo'

Я обнаружил это, потому что хотел избежать создания атрибута класса вне класса, но не смог этого сделать:

      >>> class Eggs(Spam):
...     parent = super(Eggs)
... 
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 2, in Eggs
NameError: name 'Eggs' is not defined

Однако для этого вы можете использовать атрибут экземпляра:

      >>> class Eggs(Spam):
...     def __init__(self):
...         self.Parent = super(Eggs).__get__(self, Eggs)
...
>>> eggs = Eggs()
>>> eggs.parent.bar()
'bar on Spam'
Другие вопросы по тегам