Contents

Używanie funkcji super() w klasach Pythona

Kluczowe wnioski

Wykorzystanie funkcji super() Pythona ułatwia wywoływanie metod w podklasie poprzez dostęp do jej nadklasy, usprawniając w ten sposób proces implementacji dziedziczenia i zastępowania metod w elegancki sposób.

Funkcja super() ma znaczący związek z kolejnością rozwiązywania metod (MRO) w Pythonie, która reguluje kolejność, w jakiej klasy przodków są sprawdzane pod kątem metod i właściwości podczas rozwiązywania metod.

Wykorzystanie super() w konstruktorze klasy jest zwyczajowym podejściem do ustanawiania wspólnych cech w klasie nadrzędnej przy jednoczesnym definiowaniu bardziej szczegółowych cech w klasie podrzędnej. Brak implementacji funkcji super() może skutkować niepożądanymi rezultatami, w tym pominięciem inicjalizacji atrybutów.

Jednym z podstawowych aspektów języka programowania Python jest jego paradygmat programowania obiektowego (OOP), który pozwala na tworzenie modeli reprezentujących rzeczywiste obiekty i ich wzajemne powiązania w uporządkowany sposób.

W kontekście programowania w Pythonie powszechne jest stosowanie dziedziczenia w celu modyfikowania lub zastępowania cech lub funkcji jednostki nadrzędnej klasy. Język oferuje wygodny mechanizm znany jako funkcja “super()”, która umożliwia wywoływanie metod klasy nadrzędnej z poziomu klasy podrzędnej.

Co to jest super() i dlaczego jest potrzebne?

Dziedziczenie z istniejącej klasy pozwala na utworzenie nowej klasy o podobnych atrybutach i zachowaniach poprzez proces dziedziczenia. Dodatkowo można zdecydować się na nadpisanie określonych metod w podklasie, aby zapewnić własną, unikalną implementację. Chociaż ta nowa funkcjonalność może być pożądana, istnieją przypadki, w których preferowane jest jednoczesne wykorzystanie zarówno oryginalnych, jak i nowo zaimplementowanych funkcji. W takich przypadkach użycie funkcji super() umożliwia integrację obu zestawów funkcji w podklasie.

Aby wykorzystać atrybuty i metody nadklasy w programowaniu obiektowym, można użyć funkcji super() . Funkcja ta odgrywa kluczową rolę, ponieważ ułatwia implementację dziedziczenia i nadpisywania metod, które są podstawowymi pojęciami w programowaniu obiektowym.

Jak działa super()?

Wewnętrznie, zachowanie funkcji super() jest powiązane z koncepcją Method Resolution Order (MRO), mechanizmem, który jest określany przez algorytm linearyzacji C3 w Pythonie.

Oto jak działa super():

Podczas wywoływania super() w metodzie podklasy w Pythonie, język automatycznie identyfikuje zarówno bieżącą klasę, która zawiera metodę wywołującą, jak i instancję tej klasy reprezentowaną przez self .

⭐ Określenie nadklasy: super() przyjmuje dwa argumenty - bieżącą klasę i instancję - których nie trzeba przekazywać jawnie. Używa tych informacji do określenia nadklasy do delegowania wywołania metody. Robi to poprzez sprawdzenie hierarchii klas i MRO.

Po zidentyfikowaniu nadklasy, funkcja super() pozwala na wywoływanie jej metod tak, jakby były wywoływane bezpośrednio z podklasy. Ta możliwość ułatwia zarówno rozszerzanie, jak i zastępowanie metod nadklasy, przy jednoczesnym wykorzystaniu oryginalnej implementacji dostarczonej przez nadklasę.

Użycie super() w konstruktorze klasy

Użycie metody super() w konstruktorach klas jest powszechnym podejściem, ponieważ umożliwia inicjalizację wspólnych właściwości między klasami rodzeństwa, jednocześnie pozwalając na unikalne cechy każdego indywidualnego potomstwa.

Aby zilustrować koncepcję dziedziczenia w programowaniu obiektowym przy użyciu Pythona, możemy utworzyć klasę “Ojciec”, która służy jako klasa bazowa dla innej klasy o nazwie “Syn”. Klasa “Syn” będzie dziedziczyć właściwości i metody ze swojej klasy nadrzędnej, “Ojca”, demonstrując w ten sposób, w jaki sposób dziedziczenie pozwala na ponowne wykorzystanie kodu i modułowość.

 class Father:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

class Son(Father):
    def __init__(self, first_name, last_name, age, hobby):
        # Call the parent class constructor (Father)
        super().__init__(first_name, last_name)

        self.age = age
        self.hobby = hobby

    def get_info(self):
        return f"Son's Name: {self.first_name} {self.last_name}, \
Son's Age: {self.age}, Son's Hobby: {self.hobby}"

# Create an instance of the Son class
son = Son("Pius", "Effiong", 25, "Playing Guitar")

# Access attributes
print(son.get_info())

W ramach konstruktora klasy Son , imperatyw wezwania pod auspicjami klasy nadrzędnej jest wykonywany poprzez cudowny akt przywołania funkcji super() . Ta kluczowa czynność wyzwala inicjację konstruktora klasy ojcowskiej Father , oferując dwa szanowane najważniejsze kwalifikatory w postaci zmiennych first_name i last_name . W ten sposób klasa Father zachowuje zdolność do dokładnego osiągania i przypisywania tych nominalnych oznaczeń, niezależnie od instancji Son .

/pl/images/using-super-in-class-constructor.jpg

W przypadkach, gdy metoda super() nie jest wywoływana w ramach konstrukcji

 ...
class Son(Father):
    def __init__(self, first_name, last_name, age, hobby):
        self.age = age
        self.hobby = hobby
...

W przypadku próby wywołania metody get_info w tym momencie, spowoduje to wygenerowanie AttributeError , ponieważ self. first_name i self.last_name atrybuty nie zostały jeszcze zainicjalizowane.

/pl/images/trying-to-use-parent-attributes-without-super.jpg

Używanie funkcji super() w metodach klas

Można wykorzystać funkcję super() nie tylko w ramach procedur konstruktora, ale także w różnych metodach, aby rozszerzyć lub zastąpić funkcjonalność podejścia metodologicznego klasy nadrzędnej.

 class Father:
    def speak(self):
        return "Hello from Father"

class Son(Father):
    def speak(self):
        # Call the parent class's speak method using super()
        parent_greeting = super().speak()
        return f"Hello from Son\n{parent_greeting}"

# Create an instance of the Son class
son = Son()

# Call the speak method of the Son class
son_greeting = son.speak()

print(son_greeting)

Klasa Son w Pythonie została zaprojektowana do dziedziczenia właściwości i metod ze swojej klasy nadrzędnej lub Father , w tym metody speak() . Wykorzystując funkcję super().speak() w metodzie speak() klasy Son , może ona skutecznie wywoływać oryginalną metodę speak() klasy Father , jednocześnie zawierając wszelkie dodatkowe informacje lub komunikaty unikalne dla klasy Son .

/pl/images/using-super-in-class-mthod.jpg

W przypadkach, gdy metoda nadpisuje inną bez użycia dostarczonej funkcji super() , zamierzona funkcjonalność z klasy nadrzędnej nie zostanie wykonana. W konsekwencji może to spowodować niezamierzone zachowanie z powodu zupełnie nowej i odrębnej metodologii zastępującej oryginalną funkcjonalność.

Zrozumienie Method Resolution Order

Method Resolution Order (MRO) odnosi się do hierarchii pierwszeństwa, która określa kolejność, w jakiej Python będzie szukał metod i atrybutów, gdy mamy do czynienia ze złożonymi strukturami klas obejmującymi wielokrotne dziedziczenie. Mechanizm ten zapewnia, że odpowiednia metoda jest wywoływana w oparciu o dostępne opcje w odpowiednich klasach nadrzędnych, rozwiązując w ten sposób wszelkie potencjalne niejasności wynikające z nakładających się definicji.

 class Nigeria():
    def culture(self):
        print("Nigeria's culture")

class Africa():
   def culture(self):
       print("Africa's culture") 

Podczas tworzenia instancji klasy Lagos i wywoływania jej metody culture, zachodzi szereg zdarzeń, które przyczyniają się do ogólnej funkcjonalności obiektu. Wykonanie kodu przechodzi przez kilka etapów obejmujących manipulację danymi, pobieranie informacji ze źródeł zewnętrznych i stosowanie różnych algorytmów do analizy aspektów kulturowych w oparciu o parametry wejściowe dostarczone przez użytkownika lub wartości domyślne ustawione w konstruktorze. Efektem końcowym jest kompleksowa ocena atrybutów kulturowych określonego miasta reprezentowanych przez klasę Lagos.

Python najpierw wyszukuje metodę culture w samej klasie Lagos . Jeśli metoda ta zostanie wykryta i będzie dostępna, algorytm przejdzie do jej wywołania. Jeśli jednak taka metoda nie istnieje lub nie można uzyskać do niej dostępu, proces przechodzi do kolejnej fazy.

Jeśli klasa Lagos nie ma metody culture() , Python wyszuka metodę w klasach bazowych hierarchii klas, zaczynając od tych wymienionych po dwukropku ( : ), które są dziedziczone przez klasę Lagos . W tym przykładzie klasa Lagos jest zdefiniowana jako dziedzicząca najpierw z klasy Africa , a następnie z klasy Nigeria . Dlatego jeśli klasa Lagos nie zawiera własnej implementacji metody culture() , Python spróbuje zlokalizować metodę w klasie Africa przed przeszukaniem klasy Nigeria .

Poszukiwanie metody specyficznej kulturowo w danej hierarchii klas przebiega przez serię zagnieżdżonych klas, przy czym każda kolejna klasa jest sprawdzana pod kątem znalezienia w niej pożądanej metody. W przypadku, gdy metoda nie zostanie odkryta na początkowym poziomie badania, a mianowicie w klasie afrykańskiej, Python przenosi swoją uwagę na następną najwyższą klasę w strukturze hierarchicznej, która w tym przypadku odpowiada klasie nigeryjskiej. Proces ten powtarza się w miarę schodzenia w dół drzewa klas, rozciągając się od najbardziej ogólnych do najmniej szczegółowych, aż do momentu, gdy poszukiwana metoda nie może zostać zlokalizowana w żadnej z napotkanych nadklas. W tym momencie zgłaszany jest wyjątek wskazujący na nieudany wynik wyszukiwania.

/pl/images/the-mothod-resolution-order.jpg

Kolejność rozwiązywania metod (MRO) dla Lagos jest wyświetlana liniowo, zaczynając od lewej i przesuwając się w prawo.

Najczęstsze pułapki i najlepsze praktyki

Podczas korzystania z funkcji super() ważne jest, aby zdawać sobie sprawę z pewnych potencjalnych błędów w celu zapewnienia płynnego i skutecznego działania.

⭐ Należy pamiętać o kolejności rozwiązywania metod, zwłaszcza w scenariuszach wielokrotnego dziedziczenia. Jeśli musisz użyć złożonego dziedziczenia wielokrotnego, powinieneś zapoznać się z algorytmem linearyzacji C3 , którego Python używa do określenia MRO.

Należy unikać zależności kołowych w hierarchii klas, ponieważ mogą one skutkować nieregularnym i trudnym do przewidzenia zachowaniem.

Podczas pracy ze skomplikowanymi hierarchiami klas, które wymagają użycia funkcji super() , kluczowe jest utrzymanie przejrzystej i dobrze udokumentowanej bazy kodu. Zapewnia to nie tylko prawidłową funkcjonalność, ale także promuje zrozumienie wśród innych programistów, którzy mogą potrzebować pracować nad kodem lub modyfikować go w przyszłości. Zapewniając zwięzłe, ale pouczające komentarze, można zwiększyć czytelność i łatwość utrzymania projektu, ułatwiając współpracę i zmniejszając potencjalne błędy lub nieporozumienia.

Używaj super() we właściwy sposób

Wykorzystanie funkcji super() w Pythonie stanowi nieodzowny aspekt paradygmatu programowania obiektowego, szczególnie w odniesieniu do ułatwiania dziedziczenia i zastępowania metod. Zrozumienie zawiłości związanych z tą funkcjonalną jednostką i przestrzeganie ustalonych najlepszych praktyk pozwala na tworzenie bardziej trwałych i zasobożernych aplikacji w ekosystemie Pythona.