A super leutánzása, hogy jobban megértsük a használatát

Egy korábbi, „Tudáselmélyítés és gyakorlás kész függvények vagy metódusok leutánzásával” című bejegyzésben arról volt szó, hogy a nyelv használatát és a nyelvi elemek megértését nagyban segítheti, ha megpróbálunk már készen rendelkezésre álló függvényeket, metódusokat vagy osztályokat emulálni, vagyis a funkcionalitásukat saját készítésű kóddal utánozni. Ilyenkor ahhoz, hogy ez sikerüljön, alaposan meg kell értenünk az utánozni kívánt nyelvi elemet.

Ebben a bejegyzésben a beépített függvények között található super leutánzásával foglalkozunk. Ez azért jó jelölt, mert néhány dolgot eleve tisztázni kell vele kapcsolatban mielőtt nekilátnánk az emulálásához.

Először is azt, hogy bár a beépített függvények között van felsorolva, de valójában a super egy osztály és nem függvény. Meghívásakor tehát egy osztálypéldány áll elő. Ennek megfelelően a kitűzött feladatunk egy osztálydefiníció előállítása lesz, amelynek neve legyen Super.

A következő annak megértése, hogy mit is csinál a super. A szerepe általában ismert, vagyis, hogy arra szolgál, hogy egy adott osztály feletti öröklési hierarchiában található metódust meg tudjunk hívni. Ezt tipikusan egy osztálydefinícióban szereplő metódus törzsében kell megtenni (általában annak első utasítássoraként). Ilyenkor sokszor elegendő, ha a super-t argumentumok nélkül hívjuk meg, és utána tesszük a meghívandó metódushivatkozást /pl., super().m1()/. Ebben az esetben a kívánt metódus vagy a közvetlen szülőé, vagy ha annak nincs ilyen, akkor valamelyik ősé.

Mivel az előbb említett egy gyakori használati eset, ezért talán kevésbé ismert, hogy a super valójában kétparaméteres. A híváskor tehát általános esetben két argumentumot kell megadni, amelyek együtt határozzák meg, hogy az öröklési hierarchia (pontosabban a metódusfeloldási sorrend, MRO) mely részében és honnantól keresse a kívánt metódust. Az első argumentum a keresés kezdetét határozza meg. A keresés az itt megadott típus után közvetlenül következő típustól kezdődik. A második argumentum azt határozza meg, hogy az a keresési öröklési lánc, amelyben keresünk, honnan kezdődjön. Ezen argumentumként nem csak típust lehet megadni, hanem egy objektumot is. Ebben az esetben a megadott objektum típusa lesz a keresési lánc kezdőtípusa.

Könnyen belátható, hogy ahhoz, hogy a keresés megfelelően végbe tudjon menni a két argumentum nem lehet független egymástól, mert nyilván az első argumentum által meghatározott kezdeti keresési típus bele kell, hogy essen a második argumentum által meghatározott keresési típusláncba. Ez úgy fogalmazható meg, hogy a második argumentum altípusa kell, hogy legyen az első argumentumnak. (Vagy ha objektumot adtunk meg másodiknak, akkor annak az első argumentum példányának kell lennie.)

Láthajuk, hogy a super két argumentuma két előre ismert típus, vagy típus és egy példány. Ebből következik az a szintén talán kevésbé ismert tény, hogy a super nem csak metódustörzsben hívható meg, hanem osztálydefiníción kívül, önállóan is.

Felmerülhet a kérdés, hogy ha a super használatához két argumentum kell, akkor, hogy lehetséges argumentum nélkül meghívni. Nos, argumentum nélkül meghívni csak példány- vagy osztálymetódusban lehet, mégpedig azért, mert ilyen esetben az interpreter adja át automatikusan a szükséges két argumentumot: a metódus első paramétere lesz a super második argumentuma, és a super első argumentuma az az osztály, amelyben a metódus definiálva van.

Amit még érdemes tudni, hogy a super rendelkezik három speciális adatattribútummal, amelyek a __thisclass__, __self__ és __self_class__. A super() első paraméterének átadott osztályt tartalmazza a __thisclass__. A második argumentumot a __self__ és annak típusát a __self_class__ tárolja.

Mindezen ismeretek birtokában már el tudjuk készíteni a super szerepét utánzó Super osztályt. Ennek definícióját láthatjuk alább. A részletes kommentek segítik a megértést.

A működést a következő tesztsorokkal ellenőrizzük:

A kiírt eredmények helyességét ellenőrizhetjük, ha itt a Super helyett super-t írunk.

Megjegyezzük, hogy a megalkotott Super osztály korlátja a beépített super-hez képest, hogy metódusban használva is mindig meg kell adni a két argumentumot, vagyis a fentebb említett automatikus argumentumátadás ennél nem működik.

E bejegyzés témájához a Python tudásépítés lépésről lépésre című e-könyv következő részei kapcsolódnak különösen: az „Öröklődés” fejezet „Származáskutatás és bizonyítás” és „Minden szülő szuper! – az ősök segítségül hívása” alfejezetei, valamint az „Attribútumműveletek befolyásolása” című fejezet.

Érdekel a Python tudásépítés lépésről lépésre az alapoktól az első asztali alkalmazásig című e-könyv.