此问题与What does 'super' do in Python?,How do I initialize the base (super) class?和Python: How do I make a subclass from a superclass?上的帖子有关,后者介绍了在SuperClass
内初始化SubClass
的两种方法
class SuperClass:
def __init__(self):
return
def superMethod(self):
return
## One version of Initiation
class SubClass(SuperClass):
def __init__(self):
SuperClass.__init__(self)
def subMethod(self):
return
或
class SuperClass:
def __init__(self):
return
def superMethod(self):
return
## Another version of Initiation
class SubClass(SuperClass):
def __init__(self):
super(SubClass, self).__init__()
def subMethod(self):
return
所以我对需要明确传递self
作为参数感到困惑
SuperClass.__init__(self)
和
super(SubClass, self).__init__()
。
(事实上,如果我致电SuperClass.__init__()
,我会收到错误
TypeError: __init__() missing 1 required positional argument: 'self'
)。但是在调用构造函数或任何其他类方法时(即:
## Calling class constructor / initiation
c = SuperClass()
k = SubClass()
## Calling class methods
c.superMethod()
k.superMethod()
k.subMethod()
),self
参数传递隐式。
我对self
关键字的理解是它与C ++中的this
指针没有什么不同,而它提供了对类实例的引用。这是对的吗?
如果始终存在当前实例(在这种情况下为SubClass
),那么为什么self
需要明确包含在SuperClass.__init__(self)
的调用中?
由于
答案 0 :(得分:2)
这只是方法绑定,与super
几乎没有关系。如果可以x.method(*args)
,Python会检查名为x
的方法的method
类型。如果找到一个,它会将函数“绑定”到x
,这样当你调用它时,x
将作为第一个参数传递,在其余参数之前。
当您通过类调用(普通)方法时,不会发生此类绑定。如果方法期望其第一个参数是一个实例(例如self
),则需要自己传递它。
这种绑定行为的实际实现非常简洁。如果Python对象具有__get__
方法(和/或__set__
或__delete__
方法,那么它们就是“描述符”,但这些方法与方法无关)。当您查找a.b
之类的属性时,Python会检查a
的类,以查看它是否具有作为描述符的属性b
。如果是,则会将a.b
翻译为type(a).b.__get__(a, type(a))
。如果b
是一个函数,它将有一个__get__
方法来实现我上面描述的绑定行为。其他类型的描述符可以具有不同的行为。例如,classmethod
装饰器用一个特殊的描述符替换一个方法,该特殊的描述符将类绑定到函数而不是实例。
Python super
创建的特殊对象处理属性查找的方式与普通对象不同,但对于此问题,细节并不重要。通过super
调用的方法的绑定行为就像我在第一段中描述的那样,因此self
在调用时会自动传递给绑定方法。关于super
唯一特别之处在于它可能绑定一个不同的函数,而不是在self
上查找相同的方法名称(这就是使用它的全部要点)。
答案 1 :(得分:1)
因为在SuperClass.__init__(self)
中,您在类上调用方法而不是实例,因此无法隐式传递。同样,您不能只是致电SubClass.subMethod()
,但可以致电SubClass.subMethod(k)
,并且它等同于k.subMethod()
。同样,如果self
引用SubClass
,则self.__init__()
表示SubClass.__init__(self)
,因此,如果您想致电SuperClass.__init
,则必须直接致电。{/ p>
答案 2 :(得分:1)
答案非常重要,可能需要一篇好文章。 Raymond Hettinger在Pycon 2015演讲中提供了super()
如何发挥作用的非常好的解释,可用here和相关的article。
我将尝试一个简短的答案,如果这还不够,我(希望社区)会扩展它。
答案有两个关键部分:
Python的super()
需要有一个被覆盖的方法被调用的对象,因此它与self一起显式传递。这不是唯一可能的实现,事实上,在Python 3中,不再需要传递自我实例。
Python super()
与Java或其他编译语言super
不同。 Python的实现旨在支持多协作继承范例,正如Hettinger的演讲中所解释的那样。
这在Python中有一个有趣的结果:super()
中的方法解析不仅取决于父类,还取决于子类(多重继承的结果)。请注意,Hettinger正在使用Python 3。
官方Python 2.7 documentation on super
也是一个很好的信息来源(在我看来,在观看演讲后能更好地理解)。
答案 3 :(得分:1)
以下示例可能会阐明一些事项:
class Example:
def method(self):
pass
>>> print(Example.method)
<unbound method Example.method>
>>> print(Example().method)
<bound method Example.method of <__main__.Example instance at 0x01EDCDF0>>
绑定方法时,将隐式传递实例。当方法未绑定时,需要显式传递实例。
其他答案肯定会提供有关绑定过程的更多详细信息,但我认为值得展示上述代码段。