从Python3的文档super()
“返回一个代理对象,该方法将方法调用委托给类型的父类或兄弟类。”这是什么意思?
假设我有以下代码:
class SuperClass():
def __init__(self):
print("__init__ from SuperClass.")
print("self object id from SuperClass: " + str(id(self)))
class SubClass(SuperClass):
def __init__(self):
print("__init__ from SubClass.")
print("self object id from SubClass: " + str(id(self)))
super().__init__()
sc = SubClass()
我得到的输出是:
__init__ from SubClass. self object id from SubClass: 140690611849200 __init__ from SuperClass. self object id from SuperClass: 140690611849200
这意味着在行super().__init__()
中,super()
返回当前对象,然后将其隐式传递给超类“__init__()
方法”。这是准确的还是我在这里遗漏了什么?
简而言之,我想了解以下内容:
运行super().__init__()
时
__init__()
以及如何?我们在super()
上调用它,所以无论返回什么,都应该从我对Python的理解到目前为止传递给__init__()
方法。self
传递给super().__init__()
?答案 0 :(得分:7)
返回一个代理对象,该方法将方法调用委托给父或 兄弟姐妹类型。
此proxy
是一个对象,充当父类的方法调用部分。这不是班级本身;相反,它只是足够的信息,因此您可以使用它来调用父类方法。
如果您致电__init__()
,您将获得自己的本地子类__init__
功能。当您调用super()
时,您将获得该代理对象,该对象将重定向到父类方法。因此,当您调用super().__init__()
时,该代理会将调用重定向到父类__init__
方法。
同样,如果您要调用super().foo
,您将从父类中获取foo
方法 - 再次由该代理重新路由。
你清楚吗?
对OP评论的回应
但这必须意味着传递此代理对象 运行super()时 init ()。 init ()对吧?
错误。代理对象就像包名,例如调用math.sqrt()。你没有将数学传递给sqrt,你用它来表示你正在使用哪个sqrt。如果您想将代理传递给 init ,则调用将是 init (super())。当然,这种说法在语义上是荒谬的。
当我们必须实际传入self时,我的例子中是sc对象。
不,你 传入sc
;这是对象创建调用的结果(内部方法__new__
),其中包括init
的调用。对于__init__
,self
对象是Python运行时系统为您创建的新项目。对于大多数类方法,第一个参数(在约定中称为self
,在其他语言中称为this
)是调用该方法的对象。
答案 1 :(得分:4)
这意味着在行
super().__init__()
中,super()
返回当前对象,然后将其隐式传递给超类“__init__()
方法”。这是准确的还是我在这里遗漏了什么?
>>> help(super)
super() -> same as super(__class__, <first argument>)
super
调用返回一个代理/包装器对象,它记住了:
调用super()
调用对象的类
正在调用super()
这听起来很完美。 super
始终在层次结构(实际上是MRO)中获取具有您正在查找的属性的 next 类的属性。因此它不返回当前对象,而是更准确地说,它返回一个对象,该对象记住足够的信息以搜索类层次结构中更高的属性。
- 究竟是什么传递给
醇>__init__()
以及如何?我们在super()
上调用它,所以无论返回什么,都应该从我对Python的理解到目前为止传递给__init__()
方法。
你几乎是对的。但super
喜欢在我们身上耍花招。 super
类定义__getattribute__
,此方法负责属性搜索。当您执行以下操作时:super().y()
,super.__getattribute__
会被称为搜索y
。找到y
后,它会将调用super
调用的实例传递给y
。此外,super
具有__get__
方法,这使得它成为描述符,我将在此省略描述符的详细信息,请参阅文档以了解更多信息。这也回答了你的第二个问题,即为什么self
没有明确传递。
*注意:super
有点不同,依赖于一些魔力。几乎所有其他类,行为都是一样的。那就是:
a = A() # A is a class
a.y() # same as A.y(a), self is a
但是super
是不同的:
class A:
def y(self):
return self
class B(A):
def y(self)
return super().y() # equivalent to: A.y(self)
b = B()
b.y() is b # True: returns b not super(), self is b not super()
答案 2 :(得分:1)
我写了一个简单的测试来调查CPython对super
的作用:
class A:
pass
class B(A):
def f(self):
return super()
@classmethod
def g(cls):
return super()
def h(selfish):
selfish = B()
return super()
class C(B):
pass
c = C()
for method in 'fgh':
super_object = getattr(c, method)()
print(super_object, super_object.__self__, super_object.__self_class__, super_object.__thisclass__) # (These methods were found using dir.)
零参数super
调用返回一个存储三件事的对象:
__self__
存储名称与方法的第一个参数匹配的对象 - 即使该名称已被重新分配。__self_class__
存储其类型,或者在类方法的情况下存储。__thisclass__
存储定义方法的类。(遗憾的是__thisclass__
是以这种方式实现的,而不是在方法上获取属性,因为它使得无法将super
的零参数形式用于元编程。)< / p>
super
返回的对象实现getattribute
,它将方法调用转发到__mro__
之后__self_class__
__thisclass__
key2
中找到的类型。< / p>