Наследование в Python: производный класс «копирует» или «ссылается» на методы в своем базовом классе? - PullRequest
0 голосов
/ 05 марта 2019

Выполнение следующего кода в Python выведет True и False.

class Foo:
    attr = 42

    def func(self):
        print "Hello"

class Foo2(Foo):
    pass

foo = Foo()
foo2 = Foo2()

print foo.attr is foo2.attr
print foo.func is foo2.func

Я понимаю, почему первый оператор print приводит к True (он оценивается как print 42 is 42), но не понимаю, почему второй оператор печатает False.

Согласно документации Python , говорится

, если запрошенный атрибут не найденв классе поиск продолжается в базовом классе

Это указывает на то, что существует только одна копия атрибута (в данном случае func), а производный класс просто ссылается наскопировать в базовый класс.Поэтому я ожидаю, что foo func - это то же самое, что foo2 * func.

Я также использовал Python Tutor для визуализации выполнения кода.Он показывает, что был создан только один func:

enter image description here

Итак, кто-то может объяснить, почему foo.func не foo2.func?

PS: аналогичный вопрос был задан для Java, и ответ на производный класс будет "ссылаться" на методы в базовом классе.

1 Ответ

1 голос
/ 05 марта 2019

Потому что foo и foo2 - это два разных экземпляра класса и подкласса.Даже если func действительно является той же ссылкой между Foo и Foo2, после создания экземпляров классов связанные методы создаются на основе этих двух различных экземпляров, поэтомуадрес памяти больше не совпадает и не является одним и тем же объектом, даже если они выполняют одно и то же:

>>> foo = Foo()             
>>> foo2 = Foo2()               
>>> foo.func

<bound method Foo.func of <__main__.Foo object at 0x072623D0>>
>>> foo2.func

<bound method Foo.func of <__main__.Foo2 object at 0x07262AD0>>  # notice the different object

Стоит отметить, что при изменении ссылки Foo.func, Foo2.func также изменится.Однако, если вы измените Foo2.func, Foo.func не изменится:

>>> Foo2.func

<function Foo.func at 0x0726B780>
>>> Foo.func

<function Foo.func at 0x0726B780>
>>> Foo.func = lambda: print("I'm new!")

>>> Foo.func

<function <lambda> at 0x0726B738>
>>> Foo2.func

<function <lambda> at 0x0726B738>  # Follows the same reference
>>> Foo2.func = lambda: print("Some other func")

>>> Foo2.func

<function <lambda> at 0x0726B780>  # New function
>>> Foo.func

<function <lambda> at 0x0726B738>  # unchanged.

И затем, если вы добавите новые методы в Foo, Foo2 также автоматически подберет его:

>>> Foo.func2 = lambda: print('hey!')

>>> Foo2.func2

<function <lambda> at 0x0726B7C8>

Но как только вы перезаписаете существующую ссылку унаследованного Foo.func, даже если вы переназначите Foo.func, Foo2.func больше не будет содержать ту же ссылку:

>>> Foo.func = lambda: print("I'm renewed!")

>>> Foo.func

<function <lambda> at 0x0726B738>  # newly assigned object
>>> Foo2.func

<function <lambda> at 0x0726B780>  # Reference remains as before
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...