Конструкторы Python и __init__

107

Почему конструкторы действительно называются «конструкторами»? Какова их цель и чем они отличаются от методов в классе?

Кроме того, может быть __init__в классе больше одного ? Я пробовал следующее, может кто-нибудь объяснить результат?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

Наконец, есть __init__ли перегрузчик операторов?

Ариндам Ройчоудхури
источник
41
Технически __init__это инициализатор . Питон конструктор является __new__. Python использует автоматическую двухфазную инициализацию - __new__возвращает действительный, но (обычно) незаселенный объект (см. boolКонтрпример), который затем __init__автоматически вызывает его. Это позволяет избежать проблем, которые возникают в таких языках, как C ++, с частично сконструированными объектами - в Python их никогда не бывает (хотя он может быть частично инициализирован). Вам почти никогда не понадобится переопределять и то, __new__и другое __init__в классе.
Тим Делани
2
@TimDelaney: Я не уверен, что вы имеете в виду под частично построенными объектами на C ++.
Себастьян Мах
11
@phresnel В C ++ тип объекта - это базовый класс (не подкласс), а в конструкторе базового класса. Вы не можете вызвать виртуальный метод в конструкторе базового класса, а подкласс предоставит реализацию. В Java вы можете вызвать метод подкласса в конструкторе базового класса, но переменные-члены подкласса будут автоматически инициализированы после конструктора базового класса (и вызова метода). В языках с двухэтапной инициализацией, таких как Python, вы можете без проблем вызывать методы в инициализаторе базового класса, а подкласс обеспечивает (или переопределяет) поведение.
Тим Делани
@TimDelaney: Ах, спасибо за разъяснения.
Себастьян Мах
4
@TimDelaney. Думаю, ваш комментарий должен заменить принятый ответ.
фламенко

Ответы:

114

В Python нет перегрузки функций, что означает, что у вас не может быть нескольких функций с одним и тем же именем, но с разными аргументами.

В вашем примере кода вы не перегружаете __init__() . Что происходит, так это то, что второе определение повторно связывает имя __init__с новым методом, делая первый метод недоступным.

Что касается вашего общего вопроса о конструкторах, то Википедия - хорошая отправная точка. Для материалов, относящихся к Python, я настоятельно рекомендую документы Python .

NPE
источник
Означает ли это, что исходный файл анализируется (интерпретируется?) Последовательно? Могу ли я быть уверен, что любая функция, которую я определил позже, перезаписывает функцию, определенную с тем же именем ранее? :( мой Q звучит глупо ... должен был это знать
0xc0de
4
@ 0xc0de: в Python определения функций на самом деле являются исполняемыми операторами и выполняются сверху вниз, так что да.
NPE
1
@ 0xc0de На самом деле происходит то, что тело класса выполняется в его собственном пространстве имен, а затем это пространство имен передается метаклассу (вместе с именем и базами). Тогда определения функций просто создают функцию с указанным телом и присваивают ей имя. Последним заданием __init__будет то, что закончится в классе.
skyking
64

Почему конструкторы действительно называются «конструкторами»?

Конструктор (названный __new__) создает и возвращает новый экземпляр класса. Таким образом, C.__new__метод класса является конструктором класса C.

Метод C.__init__экземпляра вызывается в конкретном экземпляре после его создания для его инициализации перед передачей обратно вызывающей стороне. Таким образом, этот метод является инициализатором для новых экземпляров C.

Чем они отличаются от методов в классе?

Как указано в официальной документации, __init__ вызывается после создания экземпляра . Другими методами такое лечение не проводится.

Какова их цель?

Цель конструктора C.__new__- определить настраиваемое поведение во время создания нового Cэкземпляра.

Цель инициализатора C.__init__- определить индивидуальную инициализацию каждого экземпляра Cпосле его создания.

Например, Python позволяет делать:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

Но если вы хотите, чтобы каждый экземпляр Testимел атрибут, xравный 10, вы можете поместить этот код внутрь __init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

Каждый метод экземпляра (метод, вызываемый конкретным экземпляром класса) получает экземпляр в качестве своего первого аргумента. Этот аргумент называется условно self.

Методы класса, такие как конструктор __new__, вместо этого получают класс в качестве первого аргумента.

Теперь, если вам нужны настраиваемые значения для xатрибута, все, что вам нужно сделать, это передать это значение в качестве аргумента в __init__:

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

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

Рик Погги
источник
9

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

Обычно вы их используете для создания переменных для этого объекта, например:

>>> class testing:
...     def __init__(self, init_value):
...         self.some_value = init_value

Итак, что вы могли бы сделать, так это создать объект из этого класса следующим образом:

>>> testobject = testing(5)

После этого у testobject будет объект с именем, some_valueкоторый в этом примере будет 5.

>>> testobject.some_value
5

Но вам не нужно устанавливать значение для каждого объекта, как я сделал в моем примере. Вы также можете сделать так:

>>> class testing:
...     def __init__(self):
...         self.some_value = 5

тогда значение some_value будет 5, и вам не нужно устанавливать его при создании объекта.

>>> testobject = testing()
>>> testobject.some_value
5

the >>> и ... в моем примере это не то, что вы пишете. Вот как бы это выглядело в pyshell ...

Никлас Нильссон
источник
Нет проблем, рад, что это помогло вам :)
Никлас Нильссон
1

коонструкторы вызываются автоматически, когда вы создаете новый объект, тем самым «конструируя» объект. Причина, по которой у вас может быть более одного init, заключается в том, что имена являются просто ссылками в python, и вам разрешено изменять то, что каждая переменная ссылается, когда захотите (отсюда динамическая типизация)

def func(): #now func refers to an empty funcion
    pass
...
func=5      #now func refers to the number 5
def func():
    print "something"    #now func refers to a different function

в определении вашего класса он просто сохраняет более поздний

Райан Хайнинг
источник
0

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

НЛПер
источник