super(cls, instance) 和 super(cls, subclass) 有什么区别? [英] What is the difference between super(cls, instance) and super(cls, subclass)?

查看:50
本文介绍了super(cls, instance) 和 super(cls, subclass) 有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

super(cls, instance)super(cls, subclass) 不会都返回 cls 的超类吗?

解决方案

差别很大;super() 使用类型(类)第二个参数而不是对象(实例)为您提供未绑定的方法,而不是绑定的方法(就像在类上访问这些方法一样).

我将首先解释 super() 如何与实例第二个参数一起工作.

super() 检查 self 的 MRO,找到第一个参数(typesupertype)MRO,然后找到下一个具有请求属性的对象.

演示:

<预><代码>>>>类基类(对象):... def foo(self): 返回 'BaseClass foo'...>>>类中介(BaseClass):... def foo(self): 返回'中介 foo'...>>>派生类(中介):... def foo(self): return 'Derived foo'...>>>d = 派生()>>>d.foo()'派生的 foo'>>>super(Derived, d).foo<0x10ef4de90处<__main__.Derived对象>的绑定方法Intermediary.foo>>>>超级(派生的,d). foo()'中介foo'>>>超级(中介,d).foo()'基类 foo'>>>派生.__mro__(<class '__main__.Derived'>, <class '__main__.Intermediary'>, <class '__main__.BaseClass'>, <type 'object'>)

Derived 的 MRO 为 (Derived, Intermediary, BaseClass)super() 通过使用 type(d).__mro__ 查看第二个参数来找到这个 MRO.foo 的搜索从给出的第一个参数之后的 next 类开始.

foo() 方法绑定在这里,调用即可.

如果您给 super() 一个 type 作为第二个参数,那么它将使用该类型的 MRO,例如而不是使用 type(instance).__mro__ 它只是用于 type.__mro__.然而,它没有实例来绑定方法.super(supertype, type).foo只是(未绑定的)函数对象:

<预><代码>>>>超级(中介,派生).foo<函数 BaseClass.foo 在 0x106dd6040>>>>超级(中介,派生). foo()回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中.类型错误:foo() 缺少 1 个必需的位置参数:'self'>>>超级(中介,派生). foo(d)'基类 foo'

要调用 .foo() 我必须显式传入一个 self 参数.

(在 Python 2 中,上面会返回一个 foo unbound method 对象而不是函数,但原理是一样的).

返回的方法同样来自 MRO 链中的下一个类;BaseClass.foo 在那里返回.

这取决于 function.__get__ 方法(即 描述符协议,负责绑定),因为它在传递要绑定到的类时返回自身(或者,在 Python 2 中,一个未绑定的方法).(对于classmethod 对象__get__ 在类中传递时确实返回一个绑定对象).

所以,TL;DR,对于方法 super(type, object) 返回一个 bound 方法,super(supertype, type) 返回未绑定的方法.目标是可以将此对象存储为类私有属性以避免必须继续查找类对象,请参阅 如何将 super() 与一个参数一起使用?.它的用例已在 Python 3 中完全过时,因此它是 预定弃用.

Won’t super(cls, instance) and super(cls, subclass) both return the superclass of cls?

解决方案

The difference is huge; super() with a type (class) second argument instead of an object (instance) gives you unbound methods, not bound methods (just like accessing those methods on a class would).

I'll explain first how super() works with an instance second argument.

super() inspects the MRO of self, finds the first argument (type or supertype) in the MRO, then finds the next object that has the requested attribute.

Demo:

>>> class BaseClass(object):
...     def foo(self): return 'BaseClass foo'
... 
>>> class Intermediary(BaseClass):
...     def foo(self): return 'Intermediary foo'
... 
>>> class Derived(Intermediary):
...     def foo(self): return 'Derived foo'
... 
>>> d = Derived()
>>> d.foo()
'Derived foo'
>>> super(Derived, d).foo
<bound method Intermediary.foo of <__main__.Derived object at 0x10ef4de90>>
>>> super(Derived, d).foo()
'Intermediary foo'
>>> super(Intermediary, d).foo()
'BaseClass foo'
>>> Derived.__mro__
(<class '__main__.Derived'>, <class '__main__.Intermediary'>, <class '__main__.BaseClass'>, <type 'object'>)

The MRO of Derived is (Derived, Intermediary, BaseClass); super() finds this MRO by looking at the second argument, using type(d).__mro__. The search for foo starts at the next class after the first argument given.

The foo() method is bound here, you can just call it.

If you give super() a type as the second argument, then it'll use the MRO of that type, e.g. instead of using type(instance).__mro__ it just goes for type.__mro__. However it then has no instance to bind the methods to. super(supertype, type).foo is just the (unbound) function object:

>>> super(Intermediary, Derived).foo
<function BaseClass.foo at 0x106dd6040>
>>> super(Intermediary, Derived).foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required positional argument: 'self'
>>> super(Intermediary, Derived).foo(d)
'BaseClass foo'

To call .foo() I have to explicitly pass in a self argument.

(In Python 2, the above would return a foo unbound method object instead of a function, but the principle is the same).

The method returned is also, again, from the next class in the MRO chain; BaseClass.foo was returned there.

This is down to the function.__get__ method (i.e. the descriptor protocol, responsible for binding), as it returns itself (or, in Python 2, an unbound method) when passed a class to bind to. (For classmethod objects, __get__ does return a bound object when passed in a class).

So, TL;DR, for methods super(type, object) returns a bound method, super(supertype, type) returns unbound methods. The goal was to make it possible to store this object as a class-private attribute to avoid having to keep looking up the class object, see How to use super() with one argument?. It's use-case has been obsoleted entirely in Python 3 so it is slated for deprecation.

这篇关于super(cls, instance) 和 super(cls, subclass) 有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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