为什么 super().__init__ () 在 Derived class in Python 中的行为与 super().override() 不同?

Why does super().__init__ () behave differently from super().override() in the Derived class in Python?

我想知道为什么 self.name 是 'abc' 而 super().__init__('abc' ) 被调用,但在调用 super().override() 时变为 'Nicky'?

是不是因为调用super().__init__('abc')时Derived实例还没有创建,所以Baseclass的属性是改用了?

class Base():
    def __init__(self, name):        
        self.name = name
        self.base = 'base class'
        print('Base', self.name)
        
    def override(self):
        print('Base-override', self.name) 

class Derived(Base):
    def __init__(self, name, age):
        super().__init__('abc')
        self.name = name
        self.age = age

    def override(self):
        super().override() 

d = Derived('Nicky', 20)  # Base abc
d.override() # Base-override Nicky

没什么神秘的。

您正在使用 name = 'abc 创建基础 class,然后使用 'Nicky' 覆盖 sef.name

从这段代码可以看出:

    super().__init__('abc')
    self.name = name
    self.age = age

为了执行 self.name = name,必须完成表达式 super().__init__('abc')

如果你加更多的打印,你会更好地理解它

class Base():
    def __init__(self, name):      
        print('Base1', self.__dict__)  
        self.name = name
        self.base = 'base class'
        print('Base2', self.name, self.__dict__)
        
    def override(self):
        print('Base-override', self.name) 

class Derived(Base):
    def __init__(self, name, age):
        print('Derived1', self.__dict__)
        super().__init__('abc')
        self.name = name
        self.age = age
        print('Derived2', self.name, self.__dict__)

    def override(self):
        super().override() 

d = Derived('Nicky', 20)  # Base abc
d.override() # Base-override Nicky

输出

Derived1 {}
Base1 {}
Base2 abc {'name': 'abc', 'base': 'base class'}
Derived2 Nicky {'name': 'Nicky', 'base': 'base class', 'age': 20}
Base-override Nicky

你的objectd的属性name没有不同的版本,都指的是同一个值,不要误以为name是parent 和 child class 之间的区别,毕竟,它只是相同的 object,与 class 层次结构无关。

这只是你在某个时间点最后设置的问题。在这里,当你调用 super().__init__('abc') 时,你还没有在你的 Derived.__init__() 中初始化名称“Nicky”,因此你首先看到了“abc”的值。

这与执行顺序以及您如何使用参数有关。 class 是数据的集合,并且具有一些处理该数据的函数。您可以使用 super() 从父 class.

显式调用实现

作为方法的 __init__ 或作为属性的 name 没有什么特别之处。您的调用顺序如下:

  1. Derived('Nicky', 20) 使用 object.__new__ 创建一个新的空对象,然后调用 Derived.__init__(obj, 'Nicky', 20)。请记住,此时属性字典为空。
  2. Derived.__init__(obj, 'Nicky', 20) 通过 super().
  3. 调用 Base.__init__(obj, 'abc') 开始
  4. Base.__init__(obj, 'abc')obj.name 设置为 'abc',将 obj.base 设置为 'base class'。然后 returns 将这两个属性设置在字典中。这是第一个 print 发生的地方。
  5. Derived.__init__(obj, 'Nicky', 20) 然后运行并设置 obj.name'Nicky'obj.age20。然后 returns。关键是 obj.nameBase.__init__ 所研究的属性相同:不同的方法,相同的数据。
  6. Derived('Nicky', 20) returns 新创建和初始化的对象,您将其分配给名称 d.
  7. 当您调用 d.override 或任何其他方法时,它可以访问 d.__dict__,就像之前的方法留下的一样。

除了关于如何存储和传递实例数据的课程之外,这是关于如何设计初始化程序的课程。通常,您调用 super 是为了避免在派生的 class 中做不必要的工作。在 __init__ 中,这意味着让基 class 处理名称信息。这也意味着当前实现的 override 不应该存在:无论如何都会在派生实例上调用基本实现,如果这就是您所做的全部,您实际上不需要覆盖它:

class Base():
    def __init__(self, name):        
        self.name = name
        self.base = 'base class'
        print('Base', type(self), self.name)
        
    def override(self):
        print('Base-override', type(self), self.name) 

class Derived(Base):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age

我已将 type(self) 添加到您的打印输出中,因此您可以看到它是 Derived 的一个实例,当您实例化 Derived 时调用 Base 方法。