ООП — Понимание наследования

#python #class #object #oop #inheritance

Вопрос:

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

 class A(object) :   def __init__(self, x) :  self._x = 2 * x  def m1(self, x) :  return self.m2(x)   2  def m2(self, x) :  return x - 1   class B(A) :   def m2(self, y) :  self._y = y  return self._x   self._y  

Для следующего, если бы я сказал a = A(1), какова была бы ожидаемая отдача? Инициализация умножает 1 на 2, так что теперь экземпляр x имеет значение 2. Что происходит с методом m1? он получает этот экземпляр X, но в возврате он ссылается на m2? итак, получается, что x=2 сначала передается в m2, а затем возврат 1 передается в m1? что добавляет к нему 2?

Что касается класса B, я вижу, что он изменяет унаследованный метод m2 из класса A, но значение x, добавляемое к y, является ли это унаследованным значением x из класса A?

Извините за бесконечные вопросы, но я только начинаю, и мне кажется, что это трудно осознать.

Комментарии:

1. Вот вопрос и дополнительные утверждения, которые я должен был применить. a = A(1) b = B(2) c = C(1, 1) d = D(2, 1) Что возвращает a.m1(2)?

2. Что такое C и D ?

3. Принимая x за 2 в m1, это приводит к правильному ответу 3. Но мне интересно, какое отношение a=A(1), как было указано ранее, имеет к этому вопрос?

4. @Codeman Я мог бы добавить их, если это необходимо, но я чувствовал, что понимание первого шага позволит мне завершить все остальное самостоятельно, что было бы истинным обучением, в которое я верю.

5. Очень хорошо. Не могли бы вы подробнее остановиться на «ожидаемой прибыли»? Вы говорите о m1 или m2?

Ответ №1:

Самый простой способ выяснить, что делает код, — это запустить его.

 gt;gt;gt; a = A(1) gt;gt;gt; a.m1(10) 11  

Важная вещь, которую следует отметить здесь (что, судя по вашему вопросу, звучало так, как будто вы можете быть сбиты с толку), заключается в том, что значение x , к которому вы переходите A.__init__ , не используется A.m1 ! Поэтому A.m1(x) просто возвращает x 1 независимо от того, как вы инициализировали A экземпляр.

 gt;gt;gt; a = A(1000) gt;gt;gt; a.m1(1) 2 gt;gt;gt; a.m1(10) 11 gt;gt;gt; a.m1(100) 101  

Хорошо, а что, если мы сделаем B то же самое?

 gt;gt;gt; b = B(1) gt;gt;gt; b.m1(10) 14  

Теперь все по-другому, потому B.m2 что отличается от A.m2 . Мы можем просто запустить их самостоятельно, чтобы посмотреть:

 gt;gt;gt; a.m2(10) 9 gt;gt;gt; b.m2(10) 12  

a.m2(10) равно 9, потому a.m2(x) что всегда просто x - 1 , независимо от того, что a._x есть.

Но b.m2(10) возвращается b._x 10 , что в данном случае равно 12-и поэтому b.m1(10) возвращает это плюс 2. Результаты будут другими, если мы изменим то, что b._x есть, инициализировав наше B значение другим значением:

 gt;gt;gt; b = B(2) gt;gt;gt; b.m2(10) 14 gt;gt;gt; b.m1(10) 16  

Комментарии:

1. Ах, в этом есть большой смысл! Большое вам спасибо за то, что нашли время помочь мне. Сейчас я попробую все остальное!

2. Каково значение y, введенное в m2 класса B? и как получилось, что a.m2(x) не зависит от a._x, где как b.m2 зависит? Редактировать: Я понимаю, как это зависит, так как он добавляет self._x к self._y, поэтому он использует начальный экземпляр x с новым экземпляром y, верно?

3. @AgentiDiogenes Значение y не зависит от того, что вы передаете в функции, но B(x).m2(y) зависит не только y от того, с какого момента вы используете функцию self._x from super().__init() . Для A , вы не используете self._x , поэтому m1/m2 называется как A(x).m1(y) и зависит только от y .

4. Я отмечу, что установка атрибута экземпляра в случайном методе является плохой практикой и делает понимание наследования излишне запутанным-если этот код является частью онлайн-курса, у меня возникают сомнения в том, насколько хорош курс.

Ответ №2:

Вы всегда можете отследить, что происходит:

 ... class B(A) :   def m2(self, y) :  self._y = y  return self._x   self._y  

class B тогда выглядит так Bx , как m2 переопределено:

  class Bx:   def __init__(self, x) :  self._x = 2 * x  def m1(self, x) :  return self.m2(x)   2  def m2(self, y) :  self._y = y  return self._x   self._y  

Так вот как class B это выглядит, когда он унаследовал

Комментарии:

1. Ах ,так вот как это действительно выглядит после наследования методов от А. Имеет смысл, спасибо!

Ответ №3:

Я постараюсь ответить на ваши вопросы по порядку:

  1. Если бы вы сказали a = A(1) , __init__ установил бы переменную self._x в 2 . Это не изменится, так как после этого вы никогда не редактируете self._x переменную.
    • Функции m1 и m2 могут возвращать все, что угодно, на основе x того, что вы передаете. Ты это имел в виду self._x ? И да, m2 выполнял бы , когда вы звоните m1 , m1 ибо любой номер x просто возвращался x 1 бы .
  2. a = A(1) это просто создание экземпляра класса A , методы будут работать только с just A(x).m1(y) , тогда как если бы вы включили a = A(1) , вы бы выполнили a.m1(y) .
  3. Создание экземпляра класса B с любым числом ( B(x) ) запускает __init__() функцию A ( super().init(args) ) с x переданным (попробуйте запустить ее самостоятельно с помощью чего-то подобного b = B(2); print(b._x) !). Таким образом, self._x 2 * x получается, что вы прошли за Б!
  4. Вы перезаписали метод m2() в классе B , поэтому m2() A в нем не используется метод from B .

Если у вас есть какие-либо другие вопросы, прокомментируйте, и я попытаюсь ответить на них!