如何使用带有一个参数的 super()? [英] How to use super() with one argument?
问题描述
在阅读有关 super()
,我偶然发现了以下声明:
如果省略第二个参数,则返回的超级对象未绑定.
'unbound' 是什么意思以及如何使用 super()
带一个参数?
Python 函数对象是 descriptors,Python 使用描述符协议将函数绑定到一个实例.这个过程会产生一个绑定方法.
绑定是当您调用方法时出现魔法"self
参数的原因,以及当您尝试使用该属性时使 property
对象自动调用方法的原因作为实例的属性.
super()
当您尝试使用它来查找父类上的方法时调用相同的描述符协议;super(Foo, self).bar()
将遍历 Foo
父类,直到找到一个属性 bar
,如果它是一个对象那是一个描述符,它将绑定到self
.调用 bar
然后调用绑定方法,该方法依次调用传入 self
参数作为 bar(self)
的函数.
要做到这一点,super()
对象存储了要绑定的类(第一个参数)和 self
(第二个参数),和em> self
参数的类型分别作为属性 __thisclass__
、__self__
和 __self_class__
:
查找属性时,搜索__self_class__
属性的__mro__
属性,从__thisclass__
位置开始一个位置,然后结果是绑定的.
super()
仅带有 one 参数将其 __self__
和 __self_class__
属性设置为 无
并且不能进行查找还:
对象确实支持描述符协议,所以你可以像绑定方法一样绑定它:
<预><代码>>>>超级(垃圾邮件).__get__(垃圾邮件,垃圾邮件)<超级:<类垃圾邮件">,<垃圾邮件对象>>>>>super(Spam).__get__(spam, Spam).bar()'在 Foo 上的酒吧'这意味着您可以将这样的对象存储在一个类中并使用它来遍历父方法:
<预><代码>>>>类鸡蛋(垃圾邮件):... 经过...>>>Eggs.parent = 超级(鸡蛋)>>>鸡蛋 = 鸡蛋()>>>蛋.parent<super: <class 'Eggs'>, <Eggs object>>>>>鸡蛋.parent.bar()'禁止垃圾邮件'主要用例是避免每次都使用 super()
的双参数形式重复该类:
Foo 类:def __init_subclass__(cls, **kwargs):super().__init_subclass__(**kwargs)# class-private 属性,所以子类不会相互破坏setattr(cls, f'_{cls.__name__}__parent', super(cls))定义栏(自我):返回 'bar on Foo'垃圾邮件类(Foo):定义栏(自我):返回垃圾邮件:"+ self.__parent.bar()
但是在使用类方法时会中断(因为 cls.__parent
不会绑定)并且已被 Python 3 的 super()
取代,零参数选择从闭包开始上课:
Foo 类:定义栏(自我):返回 'bar on Foo'垃圾邮件类(Foo):定义栏(自我):返回'垃圾邮件:' + super().bar()
While reading the Python documentation on super()
, I stumbled on the following statement:
If the second argument is omitted, the super object returned is unbound.
What does ‘unbound’ mean and how to use super()
with one argument?
Python function objects are descriptors, and Python uses the descriptor protocol to bind functions to an instance. This process produces a bound method.
Binding is what makes the 'magic' self
argument appear when you call a method, and what makes a property
object automatically call methods when you try to use the property as an attribute on instances.
super()
with two arguments invokes the same descriptor protocol when you try to use it to look up methods on parent classes; super(Foo, self).bar()
will traverse the Foo
parent classes until an attribute bar
is found, and if that is an object that is a descriptor, it will be bound to self
. Calling bar
then calls the bound method, which in turn calls the function passing in the self
argument as bar(self)
.
To do this, the super()
object stores both the class (first argument) and self
(second argument) to bind with, and the type of the self
argument as the attributes __thisclass__
, __self__
and __self_class__
respectively:
>>> class Foo:
... 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__
<__main__.Spam object at 0x107195c10>
>>> super(Spam, spam).__self_class__
<class '__main__.Spam'>
When looking up attributes, the __mro__
attribute of the __self_class__
attribute is searched, starting one position past the position of __thisclass__
, and the results are bound.
super()
with just one argument will have its __self__
and __self_class__
attributes set to None
and cannot do lookups yet:
>>> super(Spam)
<super: <class 'Spam'>, NULL>
>>> super(Spam).__self__ is None
True
>>> super(Spam).__self_class__ is None
True
>>> super(Spam).bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'super' object has no attribute 'bar'
The object does support the descriptor protocol, so you can bind it just like you can bind a method:
>>> super(Spam).__get__(spam, Spam)
<super: <class 'Spam'>, <Spam object>>
>>> super(Spam).__get__(spam, Spam).bar()
'bar on Foo'
This means you can store such an object on a class and use it to traverse to parent methods:
>>> class Eggs(Spam):
... pass
...
>>> Eggs.parent = super(Eggs)
>>> eggs = Eggs()
>>> eggs.parent
<super: <class 'Eggs'>, <Eggs object>>
>>> eggs.parent.bar()
'bar on Spam'
The primary use case would be to avoid having to repeat the class each time with the two-argument form of super()
:
class Foo:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
# class-private attribute so subclasses don’t clobber one another
setattr(cls, f'_{cls.__name__}__parent', super(cls))
def bar(self):
return 'bar on Foo'
class Spam(Foo):
def bar(self):
return 'spammed: ' + self.__parent.bar()
but that breaks when using a class method (since cls.__parent
won’t bind) and has been superseded by Python 3’s super()
with zero arguments which picks up the class from a closure:
class Foo:
def bar(self):
return 'bar on Foo'
class Spam(Foo):
def bar(self):
return 'spammed: ' + super().bar()
这篇关于如何使用带有一个参数的 super()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!