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

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

在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上搜索时,发现了不止一种方法。处理此问题的标准方法是什么?

In Python, consider I have the following code:

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

How do I initialize the SuperClass __init__ in the subclass? I am following the Python tutorial and it doesn’t cover that. When I searched on Google, I found more than one way of doing. What is the standard way of handling this?


回答 0

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)。

Python (until version 3) supports “old-style” and new-style classes. New-style classes are derived from object and are what you are using, and invoke their base class through super(), e.g.

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)

Because python knows about old- and new-style classes, there are different ways to invoke a base method, which is why you’ve found multiple ways of doing so.

For completeness sake, old-style classes call base methods explicitly using the base class, i.e.

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

But since you shouldn’t be using old-style anymore, I wouldn’t care about this too much.

Python 3 only knows about new-style classes (no matter if you derive from object or not).


回答 1

SuperClass.__init__(self, x)

要么

super(SubClass,self).__init__( x )

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

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

Both

SuperClass.__init__(self, x)

or

super(SubClass,self).__init__( x )

will work (I prefer the 2nd one, as it adheres more to the DRY principle).

See here: http://docs.python.org/reference/datamodel.html#basic-customization


回答 2

从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)

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

As of python 3.5.2, you can use:

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

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


回答 3

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

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')

How do I initialize the base (super) class?

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

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

Use a super object to ensure you get the next method (as a bound method) in the method resolution order. In Python 2, you need to pass the class name and self to super to lookup the bound __init__ method:

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

In Python 3, there’s a little magic that makes the arguments to super unnecessary – and as a side benefit it works a little faster:

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

Hardcoding the parent like this below prevents you from using cooperative multiple inheritance:

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

Note that __init__ may only return None – it is intended to modify the object in-place.

Something __new__

There’s another way to initialize instances – and it’s the only way for subclasses of immutable types in Python. So it’s required if you want to subclass str or tuple or another immutable object.

You might think it’s a classmethod because it gets an implicit class argument. But it’s actually a staticmethod. So you need to call __new__ with cls explicitly.

We usually return the instance from __new__, so if you do, you also need to call your base’s __new__ via super as well in your base class. So if you use both methods:

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 sidesteps a little of the weirdness of the super calls caused by __new__ being a static method, but you still need to pass cls to the non-bound __new__ method:

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')