Jedna od manje istraženih, ali značajnih osobina programskog jezika Python je mogućnost primene „magičnih“ metoda na objekte. Korišćenjem ovih specijalnih metoda, možemo razviti čistiji, intuitivniji i lakši za razumevanje kod.
Uz pomoć magičnih metoda, možemo oblikovati interfejse za interakciju sa objektima na način koji je u duhu samog Pythona. Ovaj tekst će vas uvesti u svet magičnih metoda, diskutovati o najboljim praksama pri njihovom kreiranju, kao i istražiti najčešće korišćene magične metode sa kojima se možete sresti.
Šta su magične metode?
Magične metode su specijalne metode u Pythonu koje određuju kako će se objekti ponašati kada se nad njima izvršavaju uobičajene operacije. Ove metode su prepoznatljive po tome što su im imena okružena sa dve donje crte pre i posle samog naziva metode.
Zbog toga se često nazivaju „dunder“ metodama, gde „dunder“ potiče od „double underscore“ (dvostruka donja crta). Jedna od čestih „dunder“ metoda koju ste možda već koristili je metoda `__init__()`, koja služi za definisanje konstruktora klase.
Uglavnom, „dunder“ metode se ne pozivaju direktno u vašem kodu, već ih poziva sam interpreter dok program radi.
Zašto su magične metode korisne?
Magične metode su koristan koncept u objektno orijentisanom programiranju u Pythonu. Njihovim korišćenjem definišete ponašanje vaših prilagođenih tipova podataka kada se koriste sa uobičajenim, ugrađenim operacijama. Ove operacije obuhvataju:
- Aritmetičke operacije
- Operacije poređenja
- Operacije životnog ciklusa
- Reprezentativne operacije
U narednom delu teksta objasnićemo kako primeniti magične metode koje definišu ponašanje aplikacije u svim gore navedenim kategorijama.
Kako definisati magične metode
Kao što je ranije rečeno, magične metode određuju ponašanje objekata. Stoga, one se definišu kao deo klase objekta. S obzirom da su deo klase objekta, one kao prvi argument primaju `self`, koji predstavlja referencu na sam objekat.
Mogu primiti i dodatne argumente, u zavisnosti od načina na koji će ih interpreter pozvati. Pored toga, prepoznatljive su po tome što im ime počinje i završava sa dve donje crte.
Implementacija
Većina onoga o čemu smo do sada pričali deluje teoretski i apstraktno. U ovom delu ćemo praktično implementirati jednostavnu klasu `Rectangle` (Pravougaonik).
Ova klasa će imati atribute dužine i širine. Korišćenjem metode `__init__`, možete specificirati ove atribute prilikom kreiranja instance. Osim toga, imaćete mogućnost da upoređujete različite pravougaonike i proverite da li je jedan jednak, manji ili veći od drugog, koristeći operatore `==`, `<` i `>`. Na kraju, pravougaonik treba da može da pruži smislenu tekstualnu reprezentaciju.
Podešavanje okruženja za kodiranje
Da biste pratili ovo uputstvo, biće vam potrebno Python okruženje za izvršavanje. Možete koristiti lokalno okruženje ili onlajn Python kompajler.
Kreiranje klase pravougaonika
Za početak, definišimo klasu `Rectangle`.
class Rectangle:
pass
Kreiranje metode konstruktora
Zatim, kreirajmo našu prvu magičnu metodu – metodu konstruktora klase. Ova metoda će primiti visinu i širinu i sačuvati ih kao atribute instance klase.
class Rectangle:
def __init__(self, height, width):
self.height = height
self.width = width
Kreiranje magične metode za reprezentaciju stringova
Dalje, želimo da kreiramo metodu koja omogućava našoj klasi da generiše čitljiv tekst koji predstavlja objekat. Ova metoda će se pozivati svaki put kada pozovemo funkciju `str()` prosleđujući instancu klase `Rectangle` kao argument. Takođe će se pozvati kada koristimo funkcije koje očekuju string argument, poput funkcije `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__()` treba da vrati string koji želite da predstavlja objekat. U ovom slučaju, vraćamo string u formatu `Rectangle(
Kreiranje magičnih metoda za operacije poređenja
Sada želimo da kreiramo operatore poređenja za operacije jednakosti, manje i veće. Ovo se naziva preopterećenje operatora. Da bismo ih kreirali, koristimo magične metode `__eq__`, `__lt__` i `__gt__` respektivno. Ove metode će vratiti logičku vrednost nakon poređenja površina pravougaonika.
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):
""" Provera jednakosti """
return self.height * self.width == other.height * other.width
def __lt__(self, other):
""" Provera da li je pravougaonik manji od drugog """
return self.height * self.width < other.height * other.width
def __gt__(self, other):
""" Provera da li je pravougaonik veći od drugog """
return self.height * self.width > other.height * other.width
Kao što vidite, ove metode primaju dva parametra. Prvi je trenutni pravougaonik, a drugi je vrednost sa kojom se vrši poređenje. Ova vrednost može biti druga instanca pravougaonika ili bilo koja druga vrednost. Logika poređenja i uslovi pod kojima će poređenje biti istinito u potpunosti zavise od vas.
Uobičajene magične metode
U ovom delu ćemo razmotriti neke od najčešćih magičnih metoda sa kojima ćete se verovatno sretati i koje ćete koristiti.
#1. Aritmetičke operacije
Metode za aritmetičke operacije se pozivaju kada se instanca vaše klase nalazi na levoj strani aritmetičkog znaka. Metoda se poziva sa dva argumenta, gde je prvi referenca na instancu, a drugi objekat desno od znaka. Metode i odgovarajući znakovi su sledeći:
Naziv metode | Znak | Opis |
`__add__` | `+` | Implementira sabiranje |
`__sub__` | `–` | Implementira oduzimanje |
`__mul__` | `*` | Implementira množenje |
`__div__` | `/` | Implementira deljenje |
`__floordiv__` | `//` | Implementira celobrojno deljenje |
#2. Operacije poređenja
Kao i metode za aritmetičke operacije, ove metode se pozivaju kada se instanca klase za koju su definisane nalazi levo od operatora poređenja. Takođe, pozivaju se sa dva parametra: prvi je referenca na instancu objekta, a drugi je referenca na vrednost sa desne strane znaka.
Naziv metode | Znak | Opis |
`__lt__` | `<` | Implementira poređenje „manje od“ |
`__gt__` | `>` | Implementira poređenje „veće od“ |
`__eq__` | `==` | Implementira poređenje „jednako“ |
`__le__` | `<=` | Implementira poređenje „manje ili jednako“ |
`__ge__` | `>=` | Implementira poređenje „veće ili jednako“ |
#3. Operacije životnog ciklusa
Ove metode se pozivaju kao odgovor na različite faze životnog ciklusa objekta, kao što je njegovo kreiranje ili brisanje. Konstruktor, `__init__`, spada u ovu kategoriju. Najčešće metode iz ove kategorije su navedene u tabeli ispod:
Naziv metode | Opis |
`__init__` | Konstruktor. Ova metoda se poziva prilikom kreiranja instance klase. |
`__del__` | Ova metoda se poziva kada se objekat klase briše. Može se koristiti za obavljanje operacija čišćenja, kao što je zatvaranje datoteka koje je objekat koristio. |
`__new__` | Metoda `__new__` se poziva pre konstruktora kada se kreira nova instanca klase. Ona vraća instancu klase. Najčešće nije neophodna, ali je ovde spomenuta radi kompletnosti. |
#4. Reprezentativne operacije
Naziv metode | Opis |
`__str__` | Vraća čitljiv string koji predstavlja objekat. Ova metoda se poziva kada pozovete funkciju `str()`, prosleđujući instancu klase kao argument. Takođe se poziva kada instancu prosledite funkcijama `print()` i `format()`. Namenjena je da pruži string koji je lako razumljiv krajnjem korisniku aplikacije. |
`__repr__` | Vraća string reprezentaciju objekta koja je korisna programeru. U idealnom slučaju, string treba da sadrži dovoljno informacija da se može rekreirati identična instanca objekta. |
Najbolje prakse za kreiranje magičnih metoda
Magične metode su moćan alat koji može pojednostaviti vaš kod. Međutim, važno je imati na umu sledeće stavke kada ih koristite:
- Koristite ih umereno – Prevelika primena magičnih metoda može otežati razumevanje vašeg koda. Ograničite se na implementaciju samo onih koje su neophodne.
- Uverite se da razumete implikacije metoda poput `__setattr__` i `__getattr__` pre nego što ih upotrebite.
- Dokumentujte ponašanje vaših magičnih metoda kako bi drugi programeri mogli tačno znati kako funkcionišu. Ovo im olakšava korišćenje i ispravljanje grešaka, kada je to potrebno.
Završne reči
U ovom tekstu sam predstavio magične metode kao način kreiranja klasa koje se mogu koristiti sa ugrađenim operacijama. Takođe sam objasnio kako se one definišu, a zatim smo prošli kroz primer klase koja je implementirala magične metode. Na kraju, spomenuo sam različite metode koje ćete verovatno koristiti, kao i nekoliko najboljih praksi koje treba imati na umu.
U sledećem koraku, možda ćete želeti da naučite kako da implementirate klasu `Counter` u Pythonu.