如何初始化基础(超级)类?

Jer*_*emy 116 python oop

在Python中,请考虑我有以下代码:

>>> class SuperClass(object):
    def __init__(self, x):
        self.x = x

>>> class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y
        # how do I initialize the SuperClass __init__ here?
Run Code Online (Sandbox Code Playgroud)

如何SuperClass __init__在子类中初始化?我正在关注Python教程,但它没有涵盖这一点.当我在Google上搜索时,我找到了不止一种方法.处理这个问题的标准方法是什么?

Ivo*_*ijk 138

Python(直到版本3)支持"旧式"和新式类.新式类派生自object您正在使用的类,并通过super()例如调用它们的基类

class X(object):
  def __init__(self, x):
    pass

  def doit(self, bar):
    pass

class Y(X):
  def __init__(self):
    super(Y, self).__init__(123)

  def doit(self, foo):
    return super(Y, self).doit(foo)
Run Code Online (Sandbox Code Playgroud)

因为python知道旧式和新式类,所以有不同的方法来调用基本方法,这就是为什么你找到了多种方法.

为了完整起见,旧式类使用基类显式调用基本方法,即

def doit(self, foo):
  return X.doit(self, foo)
Run Code Online (Sandbox Code Playgroud)

但既然你不应该再使用旧式了,我就不会太在意了.

Python 3只知道新式类(无论你是否派生object).

  • 从 Python 3.5.2 开始,您可以省略“super()”的参数,请参阅下面 Bob Jordan 的回答。 (3认同)

ada*_*amk 37

SuperClass.__init__(self, x)
Run Code Online (Sandbox Code Playgroud)

要么

super(SubClass,self).__init__( x )
Run Code Online (Sandbox Code Playgroud)

会工作(我更喜欢第二个,因为它更符合DRY原则).

请参见此处:http://docs.python.org/reference/datamodel.html#basic-customization

  • 错误.super仅适用于新式类,并且是使用新式类时调用基类的唯一正确方法.此外,您还需要使用旧式构造显式传递"self". (8认同)
  • @Ivo - OP 在示例中提供了一个新式类,讨论新式和旧式之间的区别毫无意义,因为没有人应该再使用旧式了。我提供的链接(到 Python 文档)表明有不止一种“正确”的方法来调用超类 `__init__`。 (2认同)

Aar*_*all 17

如何初始化基础(超级)类?

class SuperClass(object):
    def __init__(self, x):
        self.x = x

class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y
Run Code Online (Sandbox Code Playgroud)

使用super对象确保在方法解析顺序中获取下一个方法(作为绑定方法).在Python 2中,您需要传递类名和selfsuper来查找绑定__init__方法:

 class SubClass(SuperClass):
      def __init__(self, y):
          super(SubClass, self).__init__('x')
          self.y = y
Run Code Online (Sandbox Code Playgroud)

在Python 3中,有一些神奇的东西使得参数变得super不必要 - 并且作为一个附带的好处它可以更快地工作:

 class SubClass(SuperClass):
      def __init__(self, y):
          super().__init__('x')
          self.y = y
Run Code Online (Sandbox Code Playgroud)

像下面这样对父进行硬编码会阻止您使用协作多重继承:

 class SubClass(SuperClass):
      def __init__(self, y):
          SuperClass.__init__(self, 'x') # don't do this
          self.y = y
Run Code Online (Sandbox Code Playgroud)

请注意,__init__可能只返回None - 它旨在就地修改对象.

某物 __new__

还有另一种初始化实例的方法 - 它是Python中不可变类型的子类的唯一方法.所以,如果你要继承它的需要strtuple或其他不可变对象.

您可能认为它是一种类方法,因为它获得了一个隐式类参数.但它实际上是一种静态方法.所以,你需要打电话__new__cls明确.

我们通常会返回从实例__new__,因此,如果你这样做,你还需要调用你的基地的__new__通过super,以及在你的基类.因此,如果您使用这两种方法:

class SuperClass(object):
    def __new__(cls, x):
        return super(SuperClass, cls).__new__(cls)
    def __init__(self, x):
        self.x = x

class SubClass(object):
    def __new__(cls, y):
        return super(SubClass, cls).__new__(cls)

    def __init__(self, y):
        self.y = y
        super(SubClass, self).__init__('x')
Run Code Online (Sandbox Code Playgroud)

Python 3避开了由__new__静态方法引起的超级调用的一些奇怪现象,但是你仍然需要传递cls给非绑定__new__方法:

class SuperClass(object):
    def __new__(cls, x):
        return super().__new__(cls)
    def __init__(self, x):
        self.x = x

class SubClass(object):
    def __new__(cls, y):
        return super().__new__(cls)
    def __init__(self, y):
        self.y = y
        super().__init__('x')
Run Code Online (Sandbox Code Playgroud)


Bob*_*dan 16

从python 3.5.2开始,您可以使用:

class C(B):
def method(self, arg):
    super().method(arg)    # This does the same thing as:
                           # super(C, self).method(arg)
Run Code Online (Sandbox Code Playgroud)

https://docs.python.org/3/library/functions.html#super