如何使用带有一个参数的 super()? [英] How to use super() with one argument?

查看:63
本文介绍了如何使用带有一个参数的 super()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读有关 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__:

<预><代码>>>>Foo类:...定义栏(自我):...返回 'bar on Foo'...>>>垃圾邮件类(Foo):...定义栏(自我):...返回垃圾邮件栏"...>>>垃圾邮件 = 垃圾邮件()>>>超级(垃圾邮件,垃圾邮件)<超级:<类垃圾邮件">,<垃圾邮件对象>>>>>超级(垃圾邮件,垃圾邮件).__这个类__<class '__main__.Spam'>>>>超级(垃圾邮件,垃圾邮件).__self__<__main__.Spam 对象在 0x107195c10>>>>超级(垃圾邮件,垃圾邮件).__self_class__<class '__main__.Spam'>

查找属性时,搜索__self_class__属性的__mro__属性,从__thisclass__位置开始一个位置,然后结果是绑定的.

super() 仅带有 one 参数将其 __self____self_class__ 属性设置为 并且不能进行查找:

<预><代码>>>>超级(垃圾邮件)<超级:<类垃圾邮件">,NULL>>>>超级(垃圾邮件).__self__ 是无真的>>>超级(垃圾邮件).__self_class__ 是无真的>>>超级(垃圾邮件).bar回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中.AttributeError: 'super' 对象没有属性 'bar'

对象确实支持描述符协议,所以你可以像绑定方法一样绑定它:

<预><代码>>>>超级(垃圾邮件).__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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆