在python中调用超类的__init__时显式传递Self

时间:2016-04-11 18:58:06

标签: python subclass superclass super self

此问题与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)的调用中?

由于

4 个答案:

答案 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>>

绑定方法时,将隐式传递实例。当方法未绑定时,需要显式传递实例。

其他答案肯定会提供有关绑定过程的更多详细信息,但我认为值得展示上述代码段。