Vad är magiska metoder i Python och hur man använder dem

En av Pythons mindre uppmärksammade men ändå betydelsefulla egenskaper är möjligheten att använda så kallade magiska metoder på objekt. Dessa metoder gör det möjligt att skapa kod som är mer överskådlig, logisk och lätt att greppa.

Genom att utnyttja magiska metoder kan vi designa gränssnitt för interaktion med objekt som känns mer naturliga i Python. Denna artikel syftar till att introducera dig till magiska metoder, diskutera bästa tillvägagångssätt för att skapa dem samt undersöka de mest vanligt förekommande magiska metoderna.

Vad är magiska metoder?

Magiska metoder är speciella Python-metoder som definierar hur Python-objekt uppför sig när olika standardoperationer utförs på dem. Dessa metoder kännetecknas av dubbla understreck både före och efter metodnamnet.

Därför refereras de ofta till som ”dundermetoder” på grund av de dubbla understrecken. En dundermetod som du troligtvis redan stött på är __init__() som används för att definiera klasskonstruktorer.

Oftast anropas inte dundermetoder direkt i koden, utan de aktiveras av tolken när programmet körs.

Varför är magiska metoder användbara?

Magiska metoder utgör en viktig del av objektorienterad programmering i Python. De låter dig styra beteendet hos dina anpassade datatyper när de används med vanliga, inbyggda operationer. Exempel på dessa operationer inkluderar:

Aritmetiska beräkningar

🟢 Jämförelseoperationer

Livscykelhantering

🟢 Representation av objekt

I de följande avsnitten kommer vi att undersöka hur man implementerar magiska metoder för att definiera hur applikationen fungerar i alla ovan nämnda kategorier.

Hur man definierar magiska metoder

Som tidigare nämnts styr magiska metoder objektens beteende. Därför definieras de som en del av objektets klass. Eftersom de är en del av klassen, tar de in `self` som sitt första argument, vilket refererar till själva objektet.

De kan ha ytterligare argument beroende på hur de kommer att anropas av tolken. De kännetecknas av de dubbla understrecken före och efter deras namn.

Implementering

Mycket av det vi har talat om hittills har varit teoretiskt och abstrakt. I det här avsnittet kommer vi att skapa en enkel klass för en rektangel.

Denna klass kommer att ha egenskaper för höjd och bredd. Genom metoden __init__ kan du ange dessa egenskaper när en instans skapas. Dessutom kommer du att kunna jämföra olika rektanglar för att avgöra om de är lika, mindre eller större än varandra med hjälp av operatorerna ==, < och >. Slutligen ska rektangeln kunna generera en meningsfull strängrepresentation.

Konfigurera utvecklingsmiljön

För att följa denna genomgång behöver du en Python-körningsmiljö. Du kan använda en lokal installation eller en online Python-kompilator som adminvista.com.

Skapa rektangelklassen

Låt oss börja med att definiera klassen Rectangle:

class Rectangle:
    pass

Skapa konstruktormetoden

Nu skapar vi vår första magiska metod, klasskonstruktormetoden. Denna metod tar in höjd och bredd som argument och lagrar dem som attribut i klassinstansen.

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

Skapa en magisk metod för strängrepresentation

Därefter ska vi skapa en metod som låter vår klass generera en läsbar sträng för att representera objektet. Denna metod kommer att anropas när vi använder funktionen str() och skickar en instans av klassen Rectangle som argument. Metoden kommer också att användas när du anropar funktioner som förväntar sig ett strängargument, som till exempel print().

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

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

Metoden __str__() bör returnera en sträng som på ett bra sätt beskriver objektet. I det här fallet returnerar vi en sträng med formatet Rectangle(, ), där höjd och bredd är rektangelns lagrade dimensioner.

Skapa magiska metoder för jämförelseoperationer

Nu vill vi skapa jämförelseoperatorer för lika med, mindre än och större än operationer. Detta kallas för operatoröverbelastning. För att göra detta använder vi de magiska metoderna __eq__, __lt__ och __gt__. Dessa metoder returnerar ett booleskt värde efter jämförelse av rektanglarnas ytor.

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 rectangle is greater than the other one """
        return self.height * self.width > other.height * other.width

Som du ser tar dessa metoder in två parametrar. Den första är den aktuella rektangeln, och den andra är det värde som den jämförs med. Detta värde kan vara en annan Rectangle-instans eller något annat värde. Logiken för hur jämförelsen går till och villkoren för när jämförelsen ska vara sann är helt upp till dig.

Vanliga magiska metoder

I det här avsnittet kommer vi att undersöka de vanligaste magiska metoderna du kommer att stöta på och använda.

#1. Aritmetiska operationer

Aritmetiska magiska metoder anropas när en instans av din klass placeras till vänster om ett aritmetiskt tecken. Metoden aktiveras med två argument: den första är en referens till instansen, och den andra är objektet till höger om tecknet. Följande metoder och tecken används:

Namn Metod Tecken Beskrivning
Addition __add__ + Implementerar addition.
Subtraktion __sub__ Implementerar subtraktion.
Multiplikation __mul__ * Implementerar multiplikation.
Division __div__ / Implementerar division.
Heltalsdivision __floordiv__ // Implementerar heltalsdivision.

#2. Jämförelseoperationer

Precis som de aritmetiska magiska metoderna anropas dessa metoder när en instans av klassen de definieras för placeras till vänster om en jämförelseoperator. Liksom de aritmetiska metoderna anropas de också med två parametrar. Den första är en referens till instansen av objektet, och den andra är en referens till värdet på höger sida av tecknet.

Namn Metod Tecken Beskrivning
Mindre än __lt__ < Implementerar ”mindre än” jämförelse.
Större än __gt__ > Implementerar ”större än” jämförelse.
Lika med __eq__ == Implementerar ”lika med” jämförelse.
Mindre än eller lika med __le__ <= Implementerar ”mindre än eller lika med” jämförelse.
Större än eller lika med __ge__ >= Implementerar ”större än eller lika med” jämförelse.

#3. Livscykelhantering

Dessa metoder anropas som svar på olika livscykelhändelser för ett objekt, till exempel när det instansieras eller tas bort. Konstruktorn __init__ faller inom denna kategori. De vanligaste metoderna i denna kategori listas i tabellen nedan:

Namn Metod Beskrivning
Konstruktor __init__ Denna metod anropas när ett objekt av den klass den är definierad för skapas.
Destruktor __del__ Denna metod anropas när ett objekt av den klass den är definierad för tas bort. Den kan användas för att utföra städoperationer som att stänga filer.
Nytt objekt __new__ Metoden __new__ anropas först när ett objekt av den angivna klassen instansieras. Metoden anropas före konstruktorn och tar in klassen och eventuella ytterligare argument. Den returnerar en instans av klassen. Oftast är den inte särskilt användbar, men mer detaljer om den kan läsas här.

#4. Representation av objekt

Namn Metod Beskrivning
Strängrepresentation __str__ Returnerar en läsbar strängrepresentation av objektet. Denna metod anropas när du använder funktionen str() och skickar en instans av klassen som argument. Den anropas även när du använder funktionerna print() och format(). Den är avsedd att ge en sträng som är lätt att förstå för slutanvändaren av applikationen.
Utvecklarrepresentation __repr__ Returnerar en strängrepresentation av objektet som används av utvecklaren. Den returnerade strängen ska helst vara så informativ att det ska vara möjligt att skapa en identisk instans av objektet enbart baserat på strängen.

Bästa tillvägagångssätt för att skapa magiska metoder

Magiska metoder är otroligt användbara och kan förenkla koden. Det är dock viktigt att ha följande punkter i åtanke när du använder dem:

  • Använd dem sparsamt – Att implementera för många magiska metoder i dina klasser kan göra koden svår att förstå. Begränsa dig till de väsentliga.
  • Förstå prestandakonsekvenserna av metoder som __setattr__ och __getattr__ innan du använder dem.
  • Dokumentera beteendet för dina magiska metoder så att andra utvecklare kan förstå vad de gör. Detta gör det enklare att använda dem och felsöka om det behövs.

Avslutande ord

I den här artikeln introducerade jag magiska metoder som ett sätt att skapa klasser som kan användas med inbyggda operationer. Jag gick igenom hur de definieras och gav ett exempel på en klass som implementerade magiska metoder. Jag gick sedan igenom de olika metoder du troligtvis kommer att använda och gav några tips om bra tillvägagångssätt att tänka på.

Nästa steg kan vara att lära dig mer om hur du kan implementera klassen Counter i Python.