Родительский метод не вызывается в родительском классе

class A:
    def __init__(self):
        self.j = 0
        self.calc_i(865)

    def calc_i(self, i):
        self.i = 68 * i


class B(A):
    def __init__(self):
        super().__init__()
        print("i from B is", self.i)

    def calc_i(self, i):
        self.i = 37 * i


b = B()

Приведенный выше код должен вызывать метод родительского класса calc_i в соответствии с моим пониманием, потому что родительский класс будет запускать свой собственный метод, и он также не знает, где он используется в качестве родителя.

Но когда я запускаю его, он вызывает дочерний метод, где я * 37, а не родительский метод

Написав calc_i() для ребенка, вы переопределяете это имя еще до того, как будет вызвано __init__().

quamrana 17.12.2022 15:01

Когда вы переопределяете метод, он заменяет версию родительского класса вашей собственной; оригинал больше не вызывается автоматически. Если вы хотите, чтобы он вызывался явно, вам нужно написать явный код для этого, либо используя super, либо ожидая вызова A.calc_i. Заставляя его ожидать, вы можете выбрать, хотите ли вы вызывать родительскую версию до, после или где-то в середине вашей собственной (и аналогичным образом позволяет вам делать то, что вы делаете сейчас, и вообще не вызывать родитель).

Charles Duffy 17.12.2022 15:01

То, что self.calc_i вызывается A.__init__, не означает, что self.calc_i разрешается в A.calc_i. Вы не знаете, каким будет тип времени выполнения self, и именно это определяет, какой метод будет вызываться.

chepner 17.12.2022 15:22
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

потому что родительский класс будет запускать собственный метод

Нет, не будет.

Когда B.__init__ вызывает super().__init__, это тот же экземпляр B, который передается A.__init__. В результате оценка self.calc_i использует порядок разрешения метода (MRO) B, а не A, чтобы определить, какой calc_i метод вызывается. Поскольку MRO — это [B, A, object], а B определяет calc_i, этот метод вызывается self.calc_i(865).

Самое важное, что нужно помнить при написании метода, это то, что вы не знаете тип времени выполнения self. Единственное, в чем вы можете быть уверены, так это в том, что type(self) будет подклассом A, и вы не можете предсказать, какие методы будет определять этот подкласс.

Если вам абсолютно необходимо A.__init__ для вызова A.calc_i, вы должны быть явными:

def __init__(self):
    self.j = 0
    A.calc_i(self, 865)

или определите метод, имя которого абсолютно ясно дает понять, что его не следует (и нельзя без некоторых усилий) переопределять.

def __init__(self):
    self.j = 0
    self.__calc_i(self, 865)

def __calc_i(self, i):
    self.i = 68 * i

Если вы хотите, чтобы некоторые варианты использования calc_i были переопределяемыми, вы можете определить

def calc_i(self, i):
    return self.__calc_i(i)

и используйте self.__calc_i, когда это должна быть частная реализация A, и self.calc_i, когда вы согласны с подклассом, предоставляющим свой собственный.

Другие вопросы по теме