Почему при вызове функции с self в родительском классе дочерний класс фактически запускается в Python - PullRequest
1 голос
/ 22 мая 2019

У меня есть два абстрактных класса со следующим определением:

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

Наконец, у меня есть класс, который наследуетfrom 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.run, и все же D.run вызывается.

Это на самом деле не имеет смысламеня, если, когда я звоню super().__enter__ в D, self почему-то думает, что он все еще внутри D, когда он на самом деле в C.Может ли кто-нибудь просветить меня об этом?

Ответы [ 2 ]

3 голосов
/ 22 мая 2019

вы звоните C.run при вызове D.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() (а поскольку self имеет type D, это вызовет D.run -> C.run).

self не считает, что это «внутри D»;self - это типа D.


, если вы хотите получить желаемый вывод, вы можете просто не переопределить run в D;так будет называться только C.run.

1 голос
/ 22 мая 2019

def run() в D переопределяет def run() в C. Поэтому, когда вы звоните run() в C.__enter__, он фактически вызывает D.run().
Когда D.run() вызывается, super().run() вызывает C.run().

Меня так же смутило, когда я впервые узнал о наследовании классов Python, но именно так оно и работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...