Python: вызов дочернего метода внутри родительского метода из дочернего метода - PullRequest
0 голосов
/ 29 августа 2018

Я хочу иметь возможность перерабатывать метод из родительского класса, который использует второй метод в этом родительском классе. Однако второй метод переопределяется в дочернем классе. Я хочу, чтобы переработанный родительский метод использовал новый переопределенный второй метод, когда он вызывается из дочернего класса. Надеюсь, пример того, как я хочу, чтобы это работало, прояснит это:

class Parent:
    def method1(self, num):
        return num**2
    def method2(self, list_size):
        return [self.method1(i) for i in range(list_size)] #List of squares

class Child(Parent):
    def method1(self, num): #Overrides corresponding parent method
        return num**3
    def method2(self, list_size):
        return super().method2(list_size) #Returns a list of cubes using child's method 1.

Возможно ли это в python3? Или вызов метода 2 родителя также будет использовать метод 1 родителя? Я надеюсь повторно использовать большие части родительского класса, так как дочерний класс отличается лишь несколькими способами. Методы, вложенные таким образом в родительский класс, делают его более общим.

Спасибо!

РЕДАКТИРОВАТЬ: я забыл проверить это с простым кодом! Это работает так, как я хотел, если кому-то интересно!

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Краткий ответ: да. Только что попробовал слегка модифицированную версию вашего кода с отпечатками.

class Parent:
    def method1(self):
        print("Parent method1")

    def method2(self):
        print("Parent method2")
        self.method1()


class Child(Parent):
    def method1(self):
        print("Child method1")

    def method2(self):
        print("Child method2")
        super().method2()


c = Child()
c.method2()

Это вывод:

Child method2

Parent method2

Child method1

Как видите, метод method1 - дочерний.

0 голосов
/ 29 августа 2018

Да, это работает так, как вы хотите.

Вы можете легко проверить это самостоятельно. Если вы не передадите ничего кроме 0 и 1, должно быть совершенно очевидно, будут ли они в квадрате или в кубах.

И, в случаях, когда это менее очевидно, просто добавьте точку останова отладчика к Child.method1 и Parent.method1 и посмотрите, какая из них получает удар. Или добавьте print(f'Child1.method({self}, {num})') к методу и посмотрите, распечатывается ли он.


Если вы переходите с другого языка с семантикой ООС C ++ вместо семантики ОО Smalltalk, это может помочь думать об этом так: каждый метод всегда виртуален.

  • Являются ли __init__ звонки виртуальными? Да.
  • Что если вы вызовете метод во время __init__? Да.
  • Что если вы вызовете метод внутри super вызова? Да.
  • А как насчет @classmethod? Да.
  • Что если ...? Да.

Единственными исключениями являются случаи, когда вы стараетесь явно указать Python , а не , чтобы вызвать виртуальную функцию:

  • Вызов super() использует реализацию из следующего класса в цепочке MRO, потому что в этом весь смысл super.
  • Если вы захватите связанный метод родителя и вызовете его, как Parent.method1(self, num), вы, очевидно, получите Parent.method1, потому что в этом весь смысл связанных методов.
  • Если вы покопаетесь в диктатах класса и запустите протокол дескриптора вручную, вы, очевидно, получите все, что делаете вручную.

Если вы не пытаетесь понять Python с точки зрения Java и просто хотите глубже понять Python на его собственных терминах, вам нужно понять, что происходит, когда вы вызываете self.method1(i).

Во-первых, self.method1 не знает или не заботится, что вы собираетесь это назвать Это поиск атрибутов, как, скажем, self.name будет.

Способ, которым Python разрешает это, описан в Descriptor HOWTO , но упрощенная версия выглядит следующим образом:

  • Имеет ли self.__dict__ что-нибудь с именем method1? Нет.
  • Имеет ли type(self).__dict__ что-нибудь с именем method1? Да.
    • Возврат type(self).__dict__['method1'].__get__(self).

Если этот второй поиск не удался, Python перебрал бы type(self).mro() и выполнил бы один и тот же тест для каждого. Но здесь это не подходит. type(self) всегда будет Child для экземпляра Child, и Child.__dict__['method1'] существует, поэтому он связывает Child.method с self, и в результате получается self.method1.

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