Вызов по умолчанию для __init__ при создании экземпляра - PullRequest
1 голос
/ 18 июня 2020

Мне просто нужна помощь в понимании этих строк кода:

class Parent:
    def __init__(self):
        print("instance created")

parent1=Parent()
parent2=Parent.__init__(parent1)

output

instance created
instance created

Я пытаюсь понять, как конструктор вызывается в OOP для python .

В первой строке метод __init__ вызывается по умолчанию, а переданный аргумент self каким-то образом parent1?

Вторая строка - более традиционный способ, которым я бы Думал методы вызовут. Поскольку __init__ принимает в качестве аргумента экземпляр класса parent, я передал parent1, и он работает. Я понимаю, что происходит во второй строке, просто хотел спросить, что делает компьютер для создания экземпляра parent1 в первой строке.

Ответы [ 4 ]

2 голосов
/ 18 июня 2020

__init__ не является конструктором , это инициализатор . Когда Python создает объект, он фактически создается в __new__ (обычно оставляется по умолчанию, что просто создает пустой объект правого класса), который получает ссылку на класс и возвращает экземпляр (обычно пустой; атрибуты не установлены). Результирующий экземпляр передается неявно как self в __init__, который затем устанавливает атрибуты экземпляра.

Как правило, специальные методы, такие как __init__, напрямую не вызываются (кроме случаев с super() с кооперативным наследованием), вы просто позволяете Python делать это за вас. Единственный способ избежать вызова __init__ - это явно вызвать __new__ класса (что также крайне необычно).

0 голосов
/ 18 июня 2020

См. Документацию:

object.__init__(self[, ...])

Вызывается после создания экземпляра (__new__()), но до его возврата звонящему. Аргументы передаются в выражение конструктора класса.

object.__new__(cls[, ...])

Вызывается для создания нового экземпляра класса cls . __new__() - это статический c метод (в специальном регистре, поэтому вам не нужно объявлять его как таковой), который принимает в качестве первого аргумента класс, экземпляр которого был запрошен. Остальные аргументы передаются выражению конструктора объектов

Итак, под капотом в parent1 = Parent(), Python в основном делает следующее:

_temp_new_parent = Parent.__new__(Parent)  # Inherited from "object.__new__"
Parent.__init__(_temp_new_parent)
parent1 = _temp_new_parent

(_temp_new_parent на самом деле не существует, я просто использую его как абстракцию.)

Обратите внимание, что __init__() ничего не возвращает, поэтому в вашем коде parent2 is None. И если бы __init__() установил атрибуты экземпляра, он бы установил их на parent1, так как это то, что вы передали.

0 голосов
/ 18 июня 2020

Вы правы, что __init__() работает как конструктор, автоматически запускается при создании экземпляра объекта (как это произошло бы с конструктором Java, если это поможет). Хотя вы можете вызывать __init__, вы не должны вызывать функции / методы, начинающиеся с _ или __, они предназначены для вызова из класса / объекта.

Когда появляется self в качестве параметра в методе класса вам не нужно указывать имя объекта, Python выяснит это. Таким образом, вторая строка выше (Parent2 = ...) не рекомендуется.

0 голосов
/ 18 июня 2020

__init__ эквивалентно конструктору в Python. Думайте об объектно-ориентированном языке как о языке, который имеет обязательный аргумент для функций, представляющих методы объекта, поэтому у вас всегда есть доступ к этому объекту в этой функции. Большинство языков не заставляют вас печатать так, как вы передаете this. Python использует self и заставляет вас вводить его для каждого метода. Это то же самое, просто он не выполняет дополнительную работу за вас.

Итак, когда Python создает экземпляр класса, он передает класс функции __new__ класса, генерирует объект, а затем передает этот объект к функции класса __init__ в качестве первого аргумента.

...