为什么,在父 class 上使用 self 调用函数时,子 class 实际上是 运行 in Python

Why, when calling a function with self on the parent class, the child class is actually run in Python

我有两个抽象 class 具有以下定义:

from abc import ABC, abstractmethod

class A(ABC):

    def __init__(self, lst):
        self.List = lst

    @abstractmethod
    def __enter__(self) -> 'Component':
        return self

    @abstractmethod
    def __exit__(self, *exc):
        pass

class B(ABC):

    def __init__(self, lst):
        self.List = lst

    @abstractmethod
    def run(self):
        pass

现在,我有一个 class 继承自这些:

class C(A, B):

    def __init__(self, lst):
        A.__init__(self, lst)
        B.__init__(self, lst)

    def __enter__(self) -> 'C':
        self.List.append('C.__enter__')
        self.run()
        return self

    def __exit__(self, *exc):
        self.List.append('C.__exit__')

    def run(self):
        self.List.append('C.run')

最后,我有一个 class 继承自 C:

class D(C):

    def __init__(self, lst):
        super().__init__(lst)

   def __enter__(self) -> 'D':
       self.List.append('D.__enter__')
       super().__enter__()
       return self

   def __exit__(self, *exc):
       super().__exit__()
       self.List.append('D.__exit__')

   def run(self):
       self.List.append('D.run')
       super().run()

现在,我的代码如下所示:

my_d = D( ['start'] )
with my_d:
    pass
print(my_d)

根据我对 super() 工作原理的理解,这应该产生以下结果:

[ start,
  D.__enter__,
  C.__enter__,
  C.run,
  C.__exit__,
  D.__exit__ ]

但实际发生的是:

[ start,
  D.__enter__,
  C.__enter__,
  D.run,
  C.run,
  C.__exit__,
  D.__exit__ ]

我没有明确调用 D.runD.run 却被调用了。

这对我来说没有任何意义,除非当我在 D 中调用 super().__enter__ 时,self 以某种方式认为它仍在 D 中,而实际上它在 [=20= 中].任何人都可以启发我吗?

你在调用 D.run 时调用了 C.run:

class  D(C):


def run(self):
    self.List.append('D.run')
    super().run()  # this will add 'C.run' to self.List

__exit____enter__ 相同。

D.run 从链 D.__enter__ -> C.__enter__ 调用,现在调用 self.run() (并且 selftype D 这将调用 D.run -> C.run).

self不认为是'inside D'; self 类型 D


如果你想得到你想要的输出,你可以不覆盖 D 中的 run;这样只会调用 C.run

D 中的

def run() 覆盖了 C 中的 def run()。因此,当您在 C.__enter__ 中调用 run() 时,它实际上调用了 D.run().
当调用 D.run() 时,super().run() 调用 C.run().

我第一次了解 python class 继承时同样感到困惑,但这就是它的工作原理。