Pytanie Klasy Python: Dziedziczenie a tworzenie instancji


Tworzę klasę GUI, która używa klasy Frame () jako klasy podstawowej.

W mojej metodzie init GUIclass chcę utworzyć widget Frame

Teraz mam:

class GUIclass(Frame):
    def __init__(self, parent):
        frame = Frame(self, parent)   

Ale widziałem to gdzie indziej w trzeciej linii:

Frame.__init__(self, parent)   

Jestem nowy w programowaniu, python i zdecydowanie dziedziczenia i chciałem wiedzieć, czy rozumiem różnicę między nimi poprawnie. Zrobiłem wiele badań i czytania, obiecuję, ale nie mogłem znaleźć niczego, co sprawiłoby, że było to całkowicie jasne:

W pierwszej sytuacji nie nazywam metody init, ponieważ utworzyłem obiekt Frame (ramka), a gdy obiekt jest tworzony, jego metoda init jest wywoływana niejawnie przez Pythona.

W drugim scenariuszu jeden wywołuje metodę init na klasie (co moim zdaniem jest całkowicie uzasadnione?), Ponieważ obiekt Frame nie został utworzony, więc nie zrobiłby tego automatycznie.

Czy to prawda?

Widziałem też:

frame = Frame.__init__(self, parent)   

co naprawdę mnie wyrzuciło. Czy to jest po prostu ktoś, kto robi coś zbędnego, czy też jest ku temu powód?

Dziękuję za pomoc, chcę na razie powolutku i upewnić się, że w pełni rozumiem każdą linię kodu, którą piszę, kiedy idę, a nie piszę i prowadzę cały program, który w połowie rozumiem.


11
2018-05-15 22:43


pochodzenie


Powinieneś użyć drugiego: Frame.__init__(self, parent) - Malik Brahimi
Pierwszy jest po prostu niepoprawny, ponieważ tworzy niepotrzebną ramkę w inicjalizatorze obiektu opartego na ramce. - Malik Brahimi
Druga i trzecia to super wywołania do macierzystego inicjalizatora w ramce, tak że inicjator klasy potomnej rozszerzy podstawy, a nie zastąpi podstaw. Ale nie ma potrzeby przypisywania wyniku superużywania, co powoduje, że trzeci jest nieprawidłowy. - Malik Brahimi
Najlepszym rozwiązaniem byłoby użycie super().__init__(*arguments)(zakładając, że python3) w python2 będzie to super(GUIclass, self).__init__(*arguments) (zakładając zajęcia w nowym stylu). Ponadto PEP8 upoważnia do wezwania klasy GUIClass. - Sebastian Riese
Niestety super-połączenia nie są obsługiwane w Tkinter, - Burkely91


Odpowiedzi:


Powinieneś zadzwonić

super(GUIclass, self).__init__(parent)

To jest właściwy sposób na wywoływanie (wszystkich) twoich dziedziczonych __init__() metoda (metody). W wielu przypadkach ma identyczne wyniki w porównaniu do wymienionych

Frame.__init__(self, parent)

brak tylko abstrakcji dotyczącej związków dziedziczenia i stwierdza klasę Frame jako jedyna klasa, której __init__() metodę, z którą możesz zadzwonić (więcej informacji na ten temat później).

Wspomniałem również

frame = Frame(self.parent)

jest niewłaściwy w tym kontekście. Należy do innego wzorca relacji z obiektem, a mianowicie zawartość relacja zamiast dziedzictwo związek (na który celujesz). To będzie Stwórz nowy obiekt klasy Frame zamiast inicjować Frame części siebie; w związku z tobą dziedziczenie  za Frame, więc musisz zainicjować yourself tak samo jak inicjowanie wyspecjalizowanych części (co odbywa się w pozostałej części twojej __init__() metoda). W zawartość modele relacji po prostu mieć za Frame.

A co z tą "drobną" różnicą, o której wspomniałem powyżej między dzwonieniem super(GUIclass, self).__init__(parent) i Frame.__init__(self, parent)?

Aby zrozumieć, że musisz głębiej zagłębić się w relacje dziedziczenia i różne możliwości, jakie oferują, szczególnie w przypadku dziedziczenia wielokrotnego.

Rozważmy model relacji w kształcie rombu, który wygląda następująco:

          Frame
          /   \
    GUIclass  SomeOtherClass
          \   /
       AnotherClass

W bieżącym scenariuszu masz tylko dwie lewe dwie pierwsze klasy, ale nigdy nie wiadomo, co ma nadejść, i powinieneś zawsze kodować w taki sposób, aby następny użytkownik kodu zachował wszystkie opcje.

W tym kształcie diamentu masz AnotherClass który dziedziczy GUIClass i SomeOtherClass które z kolei obaj dziedziczą Frame.

Jeśli teraz użyjesz wzoru Frame.__init__(self, parent) zarówno GUIclass i SomeOtherClass, a następnie dzwoniąc do nich __init__() metody z __init__() metoda AnotherClass spowoduje dwukrotne wywołanie Frame„s __init__() metoda. Zazwyczaj nie jest to zamierzone i dbać o to, aby tak się nie stało super połączenie zostało wymyślone. Dba o to, aby przyzwoite polecenie wywołania wywoływało każdego z nich __init__() tylko metody i dokładnie jeden raz.


8
2018-05-15 23:03



The super argumenty idą w innej kolejności. - user2357112
Dzięki, naprawiłem to. (Nigdy nie pamiętam tych poprawnie, więc jeśli mnie wyśmiewałeś, po prostu to udoskonaliłem ;-) - Alfe
To wszystko ma teraz sens, myślę, że widzę różnicę. Tak więc mam rację twierdząc, że pierwszy technicznie inicjuje ramkę, ale tworzy oddzielny obiekt ramowy, zamiast mówić, że ten obiekt ma te właściwości ramek, a następnie niektóre - wtedy niektóre są tym, co jeszcze jest w moich klasach dziecka w tym? - Burkely91
Widzę również zastosowanie w tworzeniu kodu, który nie rozpadnie się, gdy pojawi się ktoś inny, teraz robię to sam, ale mam nadzieję, że kiedyś będę programistą, więc jest to świetna rada, o której nie myślałem. jeszcze. Teraz najlepiej zacznij praktykę! Za to miałbym dziesięć, jeśli bym mógł - Burkely91
Tak, pierwszy tworzy oddzielny obiekt i nie inicjalizuje aspektu ramki self. Czy Tkinter obsługuje super: Każda klasa, która dziedziczy object obsługuje super mechanizm. Nie jestem pewien, która klasa Tkintera jest twoją klatką, ale możesz się przyjrzeć Frame.__bases__ aby sprawdzić, czy <type 'object'> jest przez nią dziedziczona. Jeśli nie jest, nie używaj super mechanizm, ale trzymaj się Frame.__init__(self, parent) wzór. - Alfe


Będziesz musiał użyć Frame.__init__(self, parent) ponieważ Tkinter nie obsługuje super-połączeń


1
2018-06-14 04:56