python - super() 可打印表示
问题描述
sup = super(B, self)
并且sup2 = super(B, B)
具有无法区分的表示,它们看起来都像这样:
<super: <class 'B'>, <B object>>
whilesuper(B, self).spam
给出了一个绑定方法,super(B, B)
只适用于类方法,所以super(B, B).cls_spam()
,如下所示。你不能将它用于常规方法,你会得到一个正常的功能:
class A:
@classmethod
def cls_spam(cls):
print('A.cls_spam: cls =', cls)
def spam(self):
print('A.spam: self =', self)
class B(A):
def call_spam(self):
sup = super(B, self)
print('B.call_spam: sup =', sup)
print('B.call_spam: sup.spam =', sup.spam)
print('B.call_spam: sup.cls_spam =', sup.cls_spam)
sup.spam()
sup.cls_spam()
sup2 = super(B, B)
print('B.call_spam: sup2 =', sup2)
print('B.call_spam: sup2.css_spam =', sup2.cls_spam)
# can't call sup2.spam(), not without giving it self explicitly
sup2.cls_spam()
以下交互式会话说明:
>>> b = B()
>>> b.call_spam3()
B.call_spam: sup = <super: <class 'B'>, <B object>>
B.call_spam: sup.spam = <bound method A.spam of <__main__.B object at 0x108830b50>>
B.call_spam: sup.cls_spam = <bound method A.cls_spam of <class '__main__.B'>>
A.spam: self = <__main__.B object at 0x108830b50>
A.cls_spam: cls = <class '__main__.B'>
B.call_spam: sup2 = <super: <class 'B'>, <B object>>
B.call_spam: sup2.css_spam = <bound method A.cls_spam of <class '__main__.B'>>
A.cls_spam: cls = <class '__main__.B'>
super()
是一个复杂的主题,如果上面展示的行为被记录在案,这将对我有很大帮助。
使用 Python 3.5.3,Debian GNU/Linux 9.11(拉伸)
解决方案
super()
意味着在类方法和常规方法中都有用。在classmethod
没有实例的情况下,您只能访问类,因此第二个参数super()
接受实例或类。这至少包含在以下文档中super()
:
如果第二个参数是一个对象,则
isinstance(obj, type)
必须为真。如果第二个参数是类型,则issubclass(type2, type)
必须为真(这对类方法很有用)。
大胆强调我的。
现在,必须执行的主要任务super()
是在给定起点的情况下,沿着类的方法解析顺序 (MRO) 列表搜索属性。起点是第一个参数,但 MRO 必须取自第二个参数;如果您super()
在 class中使用Foo
,您当时无法知道是否Foo
可能已被子类化,这可能会改变第二个参数的 MRO。因此,为此目的,super()
跟踪两条信息:
- 您要用作搜索起点的类(第一个参数)
- 从中获取 MRO 的类(如果是实例,则为第二个参数的类型,如果是类,则为第二个参数)。
当您进行属性查找时,还有第三条信息,即属性绑定到的实例或类。这只是第二个参数本身,所以要么是实例,要么是类。repr()
输出只反映了前两个值,很大程度上是因为它们是“隐藏的” super()
,没有参数,从上下文中获取参数,所以你不能很容易地看到起点是什么,或者 MRO 是什么source 是,但您可以更容易地看到方法的第一个参数(soself
或cls
)。
如果你想区分你的两个super()
实例,你可以查看__self__
属性,它代表第三条信息:
>>> sup = super(B, b)
>>> sup.__self__
<__main__.B object at 0x108b4c520>
>>> sup2 = super(B, B)
>>> sup2.__self__
<class '__main__.B'>
repr()
您在输出中看到的另外两条信息分别是__thisclass__
和__self_class__
属性:
>>> sup.__thisclass__, sup.__self_class__
(<class '__main__.B'>, <class '__main__.B'>)
当您使用不同的类作为第一个参数时,这更容易发现:
>>> sup_a = super(A, b)
>>> sup_a
<super: <class 'A'>, <B object>>
>>> sup_a.__thisclass__, sup_a.__self_class__
(<class '__main__.A'>, <class '__main__.B'>)
推荐阅读
- angular - angular 6 ng-select 如何使用模板表达式设置下拉列表中选择的项目
- python - Python登录恢复系统的问题
- android - Android Auto 启动时的 Intent 过滤器
- javascript - Javascript“镜像”一个数字
- nextflow - “混合”操作员不等待上游进程完成
- php - 科学计数法到正常十进制输出的转换
- ruby-on-rails - 将过滤器应用于 Rails 模型
- java - 如何对嵌套地图进行分组
- c# - 如何知道网络接口何时使用路由器作为 C# 中的 DNS 服务器?
- javascript - JavaScript 错误:未捕获(承诺中)DOMException