Как я могу использовать 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'