Använda funktionen super() i Python-klasser

Viktiga takeaways

  • Pythons super()-funktion låter dig anropa superklassmetoder från en underklass, vilket gör det lättare att implementera arv och metodöverstyrning.
  • Super()-funktionen är nära relaterad till Method Resolution Order (MRO) i Python, som bestämmer i vilken ordning förfäderklasser söks efter metoder eller attribut.
  • Att använda super() i klasskonstruktörer är vanligt att initiera vanliga attribut i den överordnade klassen och mer specifika i den underordnade klassen. Att misslyckas med att använda super() kan leda till oavsiktliga konsekvenser, som att attributinitiering saknas.

En av kärnfunktionerna i Python är dess OOP-paradigm, som du kan använda för att modellera verkliga enheter och deras relationer.

När du arbetar med Python-klasser använder du ofta arv och åsidosätter en superklasss attribut eller metoder. Python tillhandahåller en super()-funktion som låter dig anropa superklassens metoder från underklassen.

Vad är super() och varför behöver du det?

Genom att använda arv kan du skapa en ny Python-klass som ärver funktionerna i en befintlig klass. Du kan också åsidosätta metoder för superklassen i underklassen, vilket ger alternativa implementeringar. Men du kanske vill använda den nya funktionen utöver den gamla istället för den. I det här fallet är super() användbar.

Du kan använda funktionen super() för att komma åt superklassattribut och anropa metoder för superklassen. Super är väsentligt för objektorienterad programmering eftersom det gör det lättare att implementera arv och metodöverstyrning.

Hur fungerar super()?

Internt är super() nära relaterat till Method Resolution Order (MRO) i Python, som C3-lineariseringsalgoritmen bestämmer.

Så här fungerar super():

  • Bestäm den aktuella klassen och instansen: När du anropar super() i en metod av en underklass, räknar Python automatiskt ut den aktuella klassen (klassen som innehåller metoden som anropade super()) och instansen av den klassen (dvs. själv) .
  • Bestäm superklassen: super() tar två argument – ​​den aktuella klassen och instansen – som du inte behöver ange uttryckligen. Den använder denna information för att bestämma superklassen för att delegera metodanropet. Den gör detta genom att undersöka klasshierarkin och MRO.
  • Anropa metoden på Superklassen: När det väl har bestämts superklassen, låter super() dig anropa dess metoder som om du anropade dem direkt från underklassen. Detta gör att du kan utöka eller åsidosätta metoder medan du fortfarande använder den ursprungliga implementeringen från superklassen.
  • Använda super() i en klasskonstruktör

    Att använda super() i en klasskonstruktor är vanligt, eftersom du ofta vill initiera vanliga attribut i den överordnade klassen och mer specifika i den underordnade.

    För att visa detta, definiera en Python-klass, Fader, som en Son-klass ärver från:

     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):
            
            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}"


    son = Son("Pius", "Effiong", 25, "Playing Guitar")


    print(son.get_info())

    Inuti Son-konstruktorn anropar anropet till super().init() klasskonstruktorn Father och skickar den förnamn och efternamn som parametrar. Detta säkerställer att Fader-klassen fortfarande kan ställa in namnattributen korrekt, även på ett Son-objekt.

    Om du inte anropar super() i en klasskonstruktor, kommer konstruktorn för dess överordnade klass inte att köras. Detta kan leda till oavsiktliga konsekvenser, såsom saknade attributinitieringar eller ofullständig inställning av den överordnade klassens tillstånd:

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

    Om du nu försöker anropa get_info-metoden kommer det att uppstå ett AttributeError eftersom attributen self.first_name och self.last_name inte har initierats.

    Använder super() i klassmetoder

    Du kan använda super() i andra metoder, förutom konstruktörer, på precis samma sätt. Detta låter dig utöka eller åsidosätta beteendet hos superklassens metod.

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

    class Son(Father):
        def speak(self):
            
            parent_greeting = super().speak()
            return f"Hello from Son\n{parent_greeting}"


    son = Son()


    son_greeting = son.speak()

    print(son_greeting)

    Son-klassen ärver från Fadern och har sin talametod. Speak-metoden för Son-klassen använder super().speak() för att anropa speak-metoden för Fader-klassen. Detta gör att den kan inkludera meddelandet från den överordnade klassen samtidigt som det utökas med ett meddelande specifikt för den underordnade klassen.

    Att misslyckas med att använda super() i en metod som åsidosätter en annan innebär att funktionaliteten som finns i den överordnade klassmetoden inte kommer att träda i kraft. Detta resulterar i en fullständig ersättning av metodbeteendet, vilket kan leda till beteende du inte tänkt.

    Förstå metodupplösningsordning

    Method Resolution Order (MRO) är den ordning i vilken Python söker efter förfäderklasser när du kommer åt en metod eller ett attribut. MRO hjälper Python att avgöra vilken metod som ska anropas när det finns flera arvshierarkier.

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

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

    Här är vad som händer när du skapar en instans av Lagos-klassen och anropar kulturmetoden:

  • Python börjar med att leta efter kulturmetoden i själva Lagos-klassen. Om den hittar den, anropar den metoden. Om inte går den vidare till steg två.
  • Om den inte hittar kulturmetoden i Lagos-klassen, tittar Python på basklasserna i den ordning de visas i klassdefinitionen. I det här fallet ärver Lagos först från Afrika och sedan från Nigeria. Så, Python kommer att leta efter kulturmetoden i Afrika först.
  • Hittar den inte kulturmetoden i Afrika-klassen så kommer Python att leta i Nigeria-klassen. Detta beteende fortsätter tills det når slutet av hierarkin och ger ett fel om det inte kan hitta metoden i någon av superklasserna.
  • Utdata visar Lagos metodupplösningsordning, med början från vänster till höger.

    Vanliga fallgropar och bästa praxis

    När du arbetar med super() finns det några vanliga fallgropar att undvika.

  • Var uppmärksam på metodupplösningsordningen, särskilt i scenarier för flera arv. Om du behöver använda komplext multipelarv bör du vara bekant med C3 Lineariseringsalgoritm som Python använder för att bestämma MRO.
  • Undvik cirkulära beroenden i din klasshierarki, vilket kan leda till oförutsägbart beteende.
  • Dokumentera din kod tydligt, särskilt när du använder super() i komplexa klasshierarkier, för att göra den mer begriplig för andra utvecklare.
  • Använd super() på rätt sätt

    Pythons super()-funktion är en kraftfull funktion när du arbetar med arv och metodöverstyrning. Att förstå hur super() fungerar och följa bästa praxis låter dig skapa mer underhållbar och effektiv kod i dina Python-projekt.