Czym są magiczne metody w Pythonie i jak ich używać

Jedną z mniej znanych, ale cennych funkcji Pythona jest możliwość implementacji magicznych metod na obiektach. Używając magicznych metod, możemy pisać czystszy kod, który jest intuicyjny i łatwy do zrozumienia.

Dzięki magicznym metodom możemy tworzyć interfejsy do interakcji z obiektami w sposób bardziej przypominający Pythona. Ten artykuł wprowadzi Cię w magiczne metody, omówi najlepsze praktyki ich tworzenia i zbada typowe magiczne metody, z którymi się spotkasz.

Czym są magiczne metody?

Magiczne metody to metody Pythona, które definiują zachowanie obiektów Pythona podczas przeprowadzania na nich typowych operacji. Metody te są wyraźnie zdefiniowane za pomocą podwójnych podkreśleń przed i po nazwie metody.

W rezultacie są one powszechnie nazywane metodami dunder, jak w przypadku podwójnego podkreślenia. Powszechną metodą, z którą mogłeś się już spotkać, jest metoda __init__() używana do definiowania konstruktorów klas.

Zazwyczaj metody dundera nie powinny być wywoływane bezpośrednio w twoim kodzie; będą raczej wywoływane przez tłumacza w trakcie działania programu.

Dlaczego metody magiczne są przydatne?

Magiczne metody są przydatną koncepcją w programowaniu obiektowym w Pythonie. Korzystając z nich, określasz zachowanie niestandardowych typów danych, gdy są one używane z typowymi, wbudowanymi operacjami. Operacje te obejmują:

🟢 Operacje arytmetyczne

🟢 Operacje porównania

🟢 Operacje cyklu życia

🟢 Operacje reprezentacyjne

W poniższej sekcji omówimy, jak zaimplementować magiczne metody, które definiują zachowanie aplikacji, gdy jest używana we wszystkich powyższych kategoriach.

Jak zdefiniować magiczne metody

Jak wspomniano wcześniej, metody magiczne określają zachowanie obiektów. Jako takie są definiowane jako część klasy obiektu. Ponieważ są częścią klasy obiektów, przyjmują jako pierwszy argument self, które jest odniesieniem do samego obiektu.

Mogą przyjmować dodatkowe argumenty w zależności od tego, jak zostaną wywołane przez tłumacza. Są one również wyraźnie zdefiniowane za pomocą dwóch podkreśleń przed i po ich nazwach.

Realizacja

Wiele z tego, co omówiliśmy do tej pory, wydaje się teoretyczne i abstrakcyjne. W tej sekcji zaimplementujemy prostą klasę Rectangle.

Ta klasa będzie miała właściwości długości i szerokości. Za pomocą metody __init__ można określić te właściwości podczas tworzenia instancji. Ponadto będziesz mógł porównywać różne prostokąty, aby zobaczyć, czy są równe, mniejsze lub większe od innego za pomocą operatorów ==, < i >. Wreszcie prostokąt powinien być w stanie zapewnić sensowną reprezentację ciągu.

Konfigurowanie środowiska kodowania

Aby postępować zgodnie z tym przewodnikiem, będziesz potrzebować środowiska uruchomieniowego języka Python. Możesz użyć lokalnego lub możesz użyć internetowego kompilatora Pythona newsblog.pl.

Tworzenie klasy Rectangle

Najpierw zacznijmy od zdefiniowania klasy Rectangle.

class Rectangle:
    pass

Tworzenie metody konstruktora

Następnie utwórzmy naszą pierwszą magiczną metodę, metodę konstruktora klas. Ta metoda pobierze wysokość i szerokość i zapisze je jako atrybuty w instancji klasy.

class Rectangle:
    def __init__(self, height, width):
        self.height = height
        self.width = width

Tworzenie magicznej metody reprezentacji łańcuchów

Następnie chcemy stworzyć metodę, która pozwoli naszej klasie wygenerować zrozumiały dla człowieka ciąg reprezentujący obiekt. Ta metoda będzie wywoływana za każdym razem, gdy wywołamy funkcję str() przekazując jako argument instancję klasy Rectangle. Ta metoda będzie również wywoływana, gdy wywołasz funkcje, które oczekują argumentu łańcuchowego, takie jak funkcja print.

class Rectangle:
    def __init__(self, height, width):
        self.height = height
        self.width = width

    def __str__(self):
        return f'Rectangle({self.height}, {self.width})'

Metoda __str__() powinna zwrócić ciąg, który ma reprezentować obiekt. W tym przypadku zwracamy ciąg znaków w formacie Rectangle(, ), gdzie wysokość i szerokość to zapisane wymiary prostokąta.

Tworzenie magicznych metod dla operacji porównawczych

Następnie chcemy utworzyć operatory porównania dla operacji równych, mniejszych niż i większych niż. Nazywa się to przeciążeniem operatora. Aby je utworzyć, używamy odpowiednio magicznych metod __eq__, __lt__ i __gt__. Te metody zwrócą wartość logiczną po porównaniu obszarów prostokątów.

class Rectangle:
    def __init__(self, height, width):
        self.height = height
        self.width = width

    def __str__(self):
        return f'Rectangle({self.height}, {self.width})'

    def __eq__(self, other):
        """ Checking for equality """
        return self.height * self.width == other.height * other.width

    def __lt__(self, other):
        """ Checking if the rectangle is less than the other one """
        return self.height * self.width < other.height * other.width

    def __gt__(self, other):
        """ Checking if the rectage is greater than the other one """
        return self.height * self.width > other.height * other.width

Jak widać, metody te przyjmują dwa parametry. Pierwszy to bieżący prostokąt, a drugi to inna wartość, z którą jest porównywany. Ta wartość może być inną instancją Rectangle lub dowolną inną wartością. Logika tego, w jaki sposób porównanie i warunki, w których porównanie zwróci wartość, zależy całkowicie od Ciebie.

Wspólne metody magiczne

W następnej sekcji omówimy popularne metody magiczne, z którymi się spotkasz i których będziesz używać.

# 1. Działania arytmetyczne

Magiczne metody arytmetyczne są wywoływane, gdy instancja twojej klasy jest umieszczana po lewej stronie znaku arytmetycznego. Metoda zostanie wywołana z dwoma argumentami, z których pierwszy będzie referencją do instancji. Druga wartość to obiekt po prawej stronie znaku. Metody i znaki są następujące:

NameMethodSignDescriptionAddition__add__+Implementuje dodawanie. Subtraction__sub__–Imlementuje odejmowanie.Multiplication__mul__*Implementuje mnożenieDivision__div__/Implementuje dzielenie.Floor distribution__floordiv__//Imlementuje dzielenie piętrowe.

#2. Operacje porównania

Podobnie jak magiczne metody arytmetyczne, metody te są wywoływane, gdy instancja klasy, dla której są zdefiniowane, znajduje się po lewej stronie operatora porównania. Ponadto, podobnie jak magiczne metody arytmetyczne, są one wywoływane z dwoma parametrami; pierwszy to odwołanie do instancji obiektu. Drugi to odniesienie do wartości po prawej stronie znaku.

NameMethodSignDescriptionLess than__lt__Implementuje większe niż porównanieEqual to__eq__==Implementuje równe porównanieLess than lub równe to__le__>=Implementuje mniejsze lub równe porównaniaGreater than lub równe__ge__<=Implementuje większe lub równe porównanie

#3. Operacje cyklu życia

Metody te będą wywoływane w odpowiedzi na różne metody cyklu życia obiektu, takie jak tworzenie instancji lub usuwanie. Konstruktor __init__ należy do tej kategorii. Typowe metody w tej kategorii są wymienione w poniższej tabeli:

NameMethodDescriptionConstructor__init__Ta metoda jest wywoływana za każdym razem, gdy usuwany jest obiekt klasy, dla której została zdefiniowana. Można jej użyć do wykonania czynności porządkowych, takich jak zamknięcie wszystkich plików, które otworzyła.Deletion__del__Ta metoda jest wywoływana za każdym razem, gdy usuwany jest obiekt klasy, dla której została zdefiniowana. Może być używany do wykonywania czynności porządkowych, takich jak zamykanie wszystkich otwartych plików. New__new__Metoda __new__ jest wywoływana jako pierwsza, gdy tworzony jest obiekt określonej klasy. Ta metoda jest wywoływana przed konstruktorem i pobiera klasę oraz wszelkie dodatkowe argumenty. Zwraca instancję klasy. W większości nie jest to zbyt przydatne, ale zostało szczegółowo omówione tutaj.

#4. Operacje reprezentacji

NameMethodDescriptionStr__str__Zwraca czytelną dla człowieka ciąg znaków reprezentujący obiekt. Ta metoda jest wywoływana, gdy wywołujesz funkcję str(), przekazując jako argument instancję klasy. Jest również wywoływana, gdy przekazujesz instancję do funkcji print() i format(). Ma na celu dostarczenie ciągu znaków zrozumiałego dla użytkownika końcowego aplikacji.Repr__repr__Zwraca ciąg reprezentujący obiekt używany przez programistę. W idealnej sytuacji zwrócony ciąg znaków powinien zawierać wiele informacji, tak aby można było zbudować identyczną instancję obiektu na podstawie samego ciągu znaków.

Najlepsze praktyki tworzenia magicznych metod

Magiczne metody są niesamowite i uprością Twój kod. Jednak podczas korzystania z nich należy pamiętać o następujących rzeczach.

  • Używaj ich oszczędnie – implementacja zbyt wielu magicznych metod w twoich klasach sprawia, że ​​twój kod jest trudny do zrozumienia. Ogranicz się do realizacji tylko tych niezbędnych.
  • Przed użyciem upewnij się, że rozumiesz wpływ metod takich jak __setatrr__ i __getattr__ na wydajność.
  • Udokumentuj zachowanie swoich magicznych metod, aby inni programiści mogli dokładnie wiedzieć, co robią. Ułatwia to im korzystanie z nich i debugowanie w razie potrzeby.

Ostatnie słowa

W tym artykule przedstawiłem metody magiczne jako sposób na tworzenie klas, których można używać z wbudowanymi operacjami. Omówiłem również sposób ich definiowania i omówiłem przykład klasy, w której zaimplementowano magiczne metody. Następnie wspomniałem o różnych metodach, których prawdopodobnie będziesz używać i których będziesz potrzebować, zanim podzielę się kilkoma najlepszymi praktykami, o których warto pamiętać.

Następnie możesz chcieć dowiedzieć się, jak zaimplementować klasę Counter w Pythonie.