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


125

在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?

如何SuperClass __init__在子类中初始化?我正在关注Python教程,但并未涵盖该内容。当我在Google上搜索时,发现了不止一种方法。处理此问题的标准方法是什么?

Answers:


146

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)

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

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

def doit(self, foo):
  return X.doit(self, foo)

但是由于您不应该再使用旧样式,因此我不会对此太在意。

Python 3只知道新型类(无论您是否派生自新object)。


37

SuperClass.__init__(self, x)

要么

super(SubClass,self).__init__( x )

会起作用(我更喜欢第二个,因为它更加遵守DRY原则)。

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


8
错误。super仅适用于新型类,并且是使用新型类时调用基的唯一正确方法。此外,您还需要使用旧式结构显式传递“ self”。
伊万·范德·维克

1
@Ivo-OP在示例中提供了一种新样式的类,谈论新样式和旧样式之间的区别毫无意义,因为没有人可以再使用旧样式。我给(指向Python文档的)链接表明,有多种“适当”的方法可以调用超类__init__
adamk 2010年


21

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

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

class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y

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

 class SubClass(SuperClass):
      def __init__(self, y):
          super(SubClass, self).__init__('x')
          self.y = y

在Python 3中,有一点魔术使参数变得super不必要了-附带的好处是它的运行速度更快:

 class SubClass(SuperClass):
      def __init__(self, y):
          super().__init__('x')
          self.y = y

像下面这样对父级进行硬编码可防止您使用协作式多重继承:

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

请注意,它__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')

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')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.