Konstruktory Pythona i __init__

107

Dlaczego faktycznie konstruktorzy są nazywani „konstruktorami”? Jaki jest ich cel i czym różnią się od metod w klasie?

Czy __init__w klasie może być więcej niż jeden ? Wypróbowałem następujące, czy ktoś może wyjaśnić wynik?

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

>>> s=test()
init 2

Wreszcie, czy __init__operator jest przeciążeniem?

Arindam Roychowdhury
źródło
41
Technicznie __init__jest inicjatorem . Pyton konstruktor jest __new__. Python używa automatycznej dwufazowej inicjalizacji - __new__zwraca prawidłowy, ale (zwykle) niezamieszkany obiekt (patrz boolprzykład przeciwny), który następnie __init__automatycznie go wywołał. Pozwala to uniknąć problemów, jakie języki takie jak C ++ mają z częściowo skonstruowanymi obiektami - nigdy nie masz takiego w Pythonie (chociaż może być częściowo zainicjowany). Będziesz prawie nigdy nie trzeba zastąpić zarówno __new__i __init__na zajęciach.
Tim Delaney,
2
@TimDelaney: Nie jestem pewien, co masz na myśli, mówiąc o częściowo skonstruowanych obiektach w C ++.
Sebastian Mach,
11
@phresnel W C ++ typ obiektu jest klasą bazową (nie podklasą), podczas gdy w konstruktorze klasy bazowej. Nie można wywołać metody wirtualnej w konstruktorze klasy bazowej, a podklasa zapewnia implementację. W Javie można wywołać metodę podklasy w konstruktorze klasy bazowej, ale zmienne składowe podklasy zostaną automatycznie zainicjowane po konstruktorze klasy bazowej (i wywołaniu metody). W językach z dwufazową inicjalizacją, takich jak Python, można szczęśliwie wywołać metody w inicjatorze klasy bazowej i sprawić, by podklasa zapewniła (lub przesłaniła) zachowanie.
Tim Delaney,
@TimDelaney: Ach, dzięki za wyjaśnienie.
Sebastian Mach,
4
@TimDelaney. Myślę, że Twój komentarz powinien zastąpić zaakceptowaną odpowiedź.
flamenco

Odpowiedzi:

114

W Pythonie nie ma przeciążenia funkcji, co oznacza, że ​​nie można mieć wielu funkcji o tej samej nazwie, ale z różnymi argumentami.

W przykładowym kodzie nie przeciążasz __init__() . Dzieje się tak, że druga definicja ponownie wiąże nazwę __init__z nową metodą, sprawiając, że pierwsza metoda jest niedostępna.

Jeśli chodzi o twoje ogólne pytanie dotyczące konstruktorów, Wikipedia jest dobrym punktem wyjścia. W przypadku rzeczy specyficznych dla Pythona bardzo polecam dokumentację Pythona .

NPE
źródło
Czy to również oznacza, że ​​plik źródłowy jest analizowany (interpretowany?) Sekwencyjnie? Czy mogę być pewien, że dowolna funkcja, którą zdefiniowałem później, nadpisze wcześniej zdefiniowaną o tej samej nazwie? :( moje Q brzmi głupio ... powinienem to wiedzieć
0xc0de,
4
@ 0xc0de: W Pythonie definicje funkcji są w rzeczywistości wykonywalnymi instrukcjami i są uruchamiane od góry do dołu, więc tak.
NPE
1
@ 0xc0de W rzeczywistości ciało klasy jest wykonywane w jej własnej przestrzeni nazw, a przestrzeń ta jest następnie przekazywana do metaklasy (wraz z nazwą i bazami). Definicje funkcji tworzą wtedy funkcję o określonej treści i przypisują ją do jej nazwy. Ostatnim zadaniem __init__będzie to, co kończy się na zajęciach.
jazda na nartach
64

Dlaczego faktycznie konstruktorzy są nazywani „konstruktorami”?

Konstruktor (o nazwie __new__) tworzy i zwraca nowe wystąpienie klasy. Zatem C.__new__metoda klasy jest konstruktorem dla klasy C.

Metoda C.__init__instancji jest wywoływana w określonej instancji po jej utworzeniu w celu jej zainicjowania przed przekazaniem z powrotem do obiektu wywołującego. Ta metoda jest więc inicjatorem dla nowych instancji C.

Czym różnią się od metod w klasie?

Jak podano w oficjalnej dokumentacji, wywoływana__init__ jest po utworzeniu instancji . Inne metody nie otrzymują tego leczenia.

Jaki jest ich cel?

Celem konstruktora C.__new__jest zdefiniowanie niestandardowego zachowania podczas tworzenia nowej Cinstancji.

Celem inicjatora C.__init__jest zdefiniowanie niestandardowej inicjalizacji każdej instancji lub Cpo jej utworzeniu.

Na przykład Python umożliwia:

class Test(object):
    pass

t = Test()

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

Ale jeśli chcesz, aby każda instancja Testmiała atrybut xrówny 10, możesz umieścić ten kod w środku __init__:

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

t = Test()
print t.x

Każda metoda instancji (metoda wywoływana na konkretnym wystąpieniu klasy) przyjmuje instancję jako pierwszy argument. Ten argument jest konwencjonalnie nazwany self.

__new__Zamiast tego metody klas, takie jak konstruktor , otrzymują klasę jako pierwszy argument.

Teraz, jeśli chcesz mieć niestandardowe wartości dla xatrybutu, wszystko, co musisz zrobić, to przekazać tę wartość jako argument do __init__:

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

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

Mam nadzieję, że pomoże Ci to rozwiać pewne wątpliwości, a skoro na inne pytania otrzymałeś już dobre odpowiedzi, na tym zakończę :)

Rik Poggi
źródło
9

Klasy to po prostu plany tworzenia obiektów z. Konstruktor to kod, który jest uruchamiany za każdym razem, gdy tworzysz obiekt. Dlatego nie ma sensu mieć dwóch konstruktorów. Dzieje się tak, że drugi nadpisuje pierwszy.

Zwykle używasz ich do tworzenia zmiennych dla tego obiektu w następujący sposób:

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

Więc to, co możesz wtedy zrobić, to utworzyć obiekt z tej klasy w następujący sposób:

>>> testobject = testing(5)

Obiekt testowy będzie miał wtedy obiekt o nazwie, some_valuektóry w tym przykładzie będzie miał wartość 5.

>>> testobject.some_value
5

Ale nie musisz ustawiać wartości dla każdego obiektu, tak jak to zrobiłem w mojej próbce. Możesz też zrobić tak:

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

wtedy wartość some_value będzie wynosić 5 i nie musisz jej ustawiać podczas tworzenia obiektu.

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

>>> i ... w mojej próbce nie jest to, co piszesz. Tak by to wyglądało w pigułce ...

Niclas Nilsson
źródło
Żaden problem, cieszę się, że ci pomogło :)
Niclas Nilsson
1

współkonstruktory są wywoływane automatycznie podczas tworzenia nowego obiektu, w ten sposób „konstruując” obiekt. Powodem, dla którego możesz mieć więcej niż jeden init, jest to, że nazwy są po prostu odwołaniami w Pythonie i możesz zmienić, do czego odwołuje się każda zmienna, kiedy tylko chcesz (stąd dynamiczne pisanie)

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

w definicji klasy zachowuje po prostu późniejszą

Ryan Haining
źródło
0

W Pythonie nie ma pojęcia przeciążania metod. Ale możesz osiągnąć podobny efekt, określając argumenty opcjonalne i słowa kluczowe

NLPer
źródło