【问题标题】:How to use super() with one argument?如何将 super() 与一个参数一起使用?
【发布时间】:2015-07-23 06:52:31
【问题描述】:

在阅读super() 上的 Python 文档时,我偶然发现了以下语句:

如果省略第二个参数,则返回的超级对象是未绑定的。

“未绑定”是什么意思以及如何将super() 与一个参数一起使用?

【问题讨论】:

标签: python super python-descriptors


【解决方案1】:

Python 函数对象是descriptors,Python 使用描述符协议将函数绑定 到一个实例。这个过程产生一个绑定方法

绑定是在您调用方法时让“神奇”self 参数出现的原因,也是在您尝试将属性用作实例的属性时让property 对象自动调用方法的原因。

super() 当你尝试使用它来查找父类上的方法时,带有两个参数的super() 会调用相同的描述符协议; super(Foo, self).bar() 将遍历Foo 父类,直到找到属性bar,如果这是一个描述符对象,它将绑定到self。调用bar 然后调用绑定方法,该方法又调用传入self 参数为bar(self) 的函数。

为此,super() 对象存储要绑定的类(第一个参数)和 self(第二个参数),self 参数的类型作为属性分别为__thisclass____self____self_class__

>>> 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'>

查找属性时,搜索__self_class__属性的__mro__属性,从__thisclass__的位置后一位开始,并绑定结果。

super() 仅具有 一个 参数将其 __self____self_class__ 属性设置为 None 并且无法进行查找

>>> 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'

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

>>> 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'

主要用例是避免每次都使用 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()

但是在使用类方法时会中断(因为 cls.__parent 不会绑定)并且已被 Python 3 的 super() 取代,零参数从闭包中获取类:

class Foo:
    def bar(self):
        return 'bar on Foo'

class Spam(Foo):
    def bar(self):
        return 'spammed: ' + super().bar()

【讨论】:

  • 非常有用的答案,因为这种行为是无证的,谢谢 Martijn。
  • 是否有内置的方式来遍历类的 MRO 并返回无限的结果?
  • @RobinDeSchepper:只需遍历 class __mro__ attribute,然后直接访问类命名空间(例如,vars(classobject) 为您提供该命名空间,一个字典)。
猜你喜欢
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多