关于python:我是否需要手动将属性从超类的“__init__”传递给子类的“__init__”,即使我使用“super()”?

Do I need to pass attributes from superclass's “__init__” to subclass's “__init__” manually, even if I use “super()”?

在下面的示例中(摘自python crash course book),为什么要将makemodelyear传递给子类__init__方法?

super()是否应该已经自动将这些参数转移到子类的__init__方法中?

1
2
3
4
5
6
7
8
9
class Car():
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

class ElectricCar(Car):
    def __init__(self, make, model, year):  
        super().__init__(make, model, year)


why do we pass make, model and year to the subclass init method?

不然它会怎么把它们传给它的超类呢?

Isn't super() supposed to already transfer those parameters to the subclass's init method automatically?

不。Super()返回MRO中下一个类的代理(cf python的"super"如何做正确的事情?更多关于super对象等)。它不是"转移"到子类,而是使用Super()来调用父类的实现的子类。

注意,在这个例子中,ElectricCar__init__方法是完全无用的——它只委托给父级,不做其他任何事情,所以您只需删除它,而父级的__init__将被自动使用。Super()的要点是在子类中专门化父类的方法时调用父类的方法,即:

1
2
3
4
5
6
7
8
9
10
class Parent():
   def __init__(self, foo):
       self.foo = foo


class Child(Parent):
   def __init__(self, foo):
       super().__init__(foo)
       # doing something more...
       self.bar = 42

虽然您的措辞不太正确(这些参数实际上是从子类传递到超类的),但答案是"是",您需要手动为super().__init__(*args, **kwargs)传递参数。否则,您将遇到一个TypeError抱怨缺少所需的位置/关键字参数。

在您的示例中,这似乎是不必要的,但您在super().__init__()之后删掉了一个关键行:

1
2
3
4
class ElectricCar(Car):
    def __init__(self, make, model, year):  
        super().__init__(make, model, year)
        self.battery = Battery()

这就需要重新定义你的子类ElectricCar中的__init__,因为Car没有battery属性。

注意,对于不可变的超类,您不需要传递任何参数:

1
2
3
4
class Foo(int):
    def __init__(self, value):
        self.value = value
        super().__init__()

它只接受你在__new__()点的子类论点。在这种情况下,如果您手动将任何参数传递给super().__init(),解释器会抱怨超类的__init__方法不接受任何参数。你很快就会明白为什么这看起来没用,但这里有一个相关的问题,就是如何正确地继承strint(如有必要)。