Конструктори 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 .


Чи це також означає, що вихідний файл аналізується (інтерпретується?) Послідовно? Чи можу я бути впевнений, яка функція, яку я визначив пізніше, замінює функцію, визначену тим самим іменем у попередньому? :( мій Q звучить нерозумно .. мав це знати
0xc0de

4
@ 0xc0de: У Python визначення функцій насправді виконуються операторами і виконуються зверху вниз, так що так.
NPE

1
@ 0xc0de Насправді відбувається те, що тіло класу виконується у власному просторі імен, а потім простір імен передається метакласу (серед імені та бази). Визначення функції тоді просто створюють функцію із зазначеним тілом та присвоюють їй своє ім'я. Останнім завданням __init__буде те, що закінчується в класі.
скачаючи

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)

Тоді у тестоб'єкта буде об’єкт, який називається 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

>>> і ... в моєму зразку не те, що ви пишете. Як би це виглядало в pyshell ...


Немає проблем, радий, що вам це допомогло :)
Niclas Nilsson

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 не існує. Але ви можете досягти подібного ефекту, вказавши необов’язкові та ключові аргументи

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.