【问题标题】:Explicit passing of Self when calling super class's __init__ in python在 python 中调用超类的 __init__ 时显式传递 Self
【发布时间】:2016-08-02 02:32:34
【问题描述】:

这个问题与 What does 'super' do in Python?How do I initialize the base (super) class?Python: How do I make a subclass from a superclass? 的帖子有关,它描述了从 SubClass 中初始化 SuperClass 的两种方法

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 参数被隐式传递

我对@9​​87654335@ 关键字的理解是,它与C++ 中的this 指针没有什么不同,但它提供了对类实例的引用。这是正确的吗?

如果总是存在当前实例(在本例中为 SubClass),那么为什么 self 需要显式包含在对 SuperClass.__init__(self) 的调用中?

谢谢

【问题讨论】:

    标签: python subclass superclass super self


    【解决方案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>>
    

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

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

    【讨论】:

      【解决方案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 上查找相同的方法名称(这就是使用它的全部意义)。

      【讨论】:

        【解决方案3】:

        答案很重要,可能需要一篇好文章。 Raymond Hettinger 在 Pycon 2015 演讲中出色地解释了 super() 的工作原理,here 和相关的 article 可用。 我将尝试一个简短的答案,如果还不够,我(希望社区)会对此进行扩展。 答案有两个关键部分:

        • Python 的super() 需要有一个对象,在该对象上调用被覆盖的方法,因此它通过 self 显式传递。这不是唯一可能的实现,事实上,在 Python 3 中,您不再需要传递 self 实例。

        • Python super() 不像 Java 或其他编译语言 super。正如 Hettinger 的演讲中所解释的,Python 的实现旨在支持 多重协作继承 范式。 这在 Python 中有一个有趣的结果:super() 中的方法解析不仅取决于父类,还取决于子类(多重继承的结果)。请注意,Hettinger 使用的是 Python 3。

        官方的 Python 2.7 documentation on super 也是一个很好的信息来源(在我看来,看完演讲更好理解)。

        【讨论】:

          【解决方案4】:

          因为在SuperClass.__init__(self) 中,您调用的是类上的方法,而不是实例,所以它不能隐式传递。同样,您不能只调用SubClass.subMethod(),但您可以调用SubClass.subMethod(k),它将等效于k.subMethod()。同样,如果self 指的是SubClass,那么self.__init__() 表示SubClass.__init__(self),所以如果你想调用SuperClass.__init,你必须直接调用它。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-02-18
            • 1970-01-01
            • 2020-01-02
            • 1970-01-01
            • 2014-03-07
            • 1970-01-01
            • 1970-01-01
            • 2020-09-27
            相关资源
            最近更新 更多