Osztályok, objektumok¶
A Python nyelvi szinten támogatja az objektumorientált programozást. Ennek köszönhetően a korábban (Programozás I és Webtervezés kurzusokon) megismert objektumorientált koncepciók Pythonban is megvalósíthatók. Ezen a gyakorlaton megnézzük, hogy hogyan.
Osztály létrehozása¶
Az osztály absztrakt fogalom, konkrét életbeli objektumok, objektumcsoportok formai leírása. Osztályokkal olyan objektumokat formalizálhatunk, amelyek azonos tulajdonságokkal és viselkedéssel rendelkeznek.
Pythonban osztályt a következő szintaxissal hozhatunk létre:
1 2 |
|
Közvetlenül az osztály neve után, zárójelek között megadhatjuk, hogy melyik osztályból öröklődünk. A Python (Javával ellentétben) támogatja a többszörös öröklődést, így egy osztály akár egyszerre több másik osztályból is öröklődhet.
A Pythonbeli öröklődési hierarchia tetején az object
névre hallgató ősosztály áll. Python 3-ban, ha ebből az object
ősosztályból származtatunk egy osztályt, akkor ezt nem szükséges expliciten kiírnunk, így class OsztalyNeve(object)
helyett azt is írhatjuk, hogy class OsztalyNeve
.
Megjegyzés
A Python 2-vel való kompatibilitás miatt korábban célszerű volt kiírni az (object)
-et az osztályunk neve után. Mivel a Python 2 már nem támogatott, így ez ma már elhagyható, de régebbi kódokban találkozhatunk ilyen jelöléssel.
Példa: A Szuperhos
osztály elkezdése
1 2 |
|
A pass
utasítás¶
A fenti kódpéldában látható pass
utasítás azt jelzi, hogy az osztályunk törzse üres, ezt majd később fogjuk megírni.
Pythonban egy blokkot (vezérlési ágat, függvénytörzset, osztálynak a törzsét stb.) nem hagyhatunk üresen - ekkor hibát kapnánk. Ha a blokkunk nem tartalmaz utasítást, akkor a pass
utasítást kell beleírnunk - ezzel jelezzük, hogy az adott blokkban nem csinálunk semmit.
Adattagok, metódusok¶
Az osztályok adattagokat és metódusokat (tagfüggvényeket) tartalmazhatnak. Ezeket a .
(pont) operátor segítségével tudjuk elérni.
Pythonban az adattagokat nem deklaráljuk külön az osztályban (mint ahogy azt Javában csináltuk), hanem a konstruktoron belül hozzuk létre és inicializáljuk őket.
A metódusok lényegében függvények az osztályon belül, így a def
kulcsszóval hozzuk létre őket. Egy fontos szabály, hogy Pythonban minden metódusnak van egy kötelező első paramétere, amit expliciten ki kell írni minden metódus fejlécében. Ezt általában self
-nek nevezzük el, és ezzel magára az objektumra tudunk hivatkozni (kb. olyan, mint Javában a this
).
Megjegyzés
Az aktuális objektumra hivatkozó azonosítót nem kötelező self
-nek elnevezni, a név tetszőleges is lehet.
Példa: Metódus létrehozása az osztályon belül
1 2 3 |
|
Konstruktor¶
A konstruktor az osztály példányosítása során (tehát a konkrét objektumpéldányok létrehozásakor) lefutó, speciális metódus. Pythonban az __init__
metódus tekinthető konstruktornak, ezt használjuk az adattagok létrehozására és inicializálására.
A konstruktor szintaxisa (a szögletes zárójelek közötti részek elhagyhatók):
1 2 3 |
|
Példa: A szuperhősökről eltároljuk a nevüket és a szupererejüket. Hozzunk létre egy olyan konstruktort a Szuperhos
osztályban, amely paraméterül kapja a nevet és a szupererőt, és ezekkel az értékekkel inicializálja az adattagokat!
1 2 3 4 |
|
Pythonban továbbra sincs function overload. Ha azt szeretnénk elérni, hogy egy metódust többféle, eltérő paraméterezéssel is tudjunk használni, akkor használjuk a default függvényparamétereket.
Példa: Írjuk át a Szuperhos
osztály konstruktorát úgy, hogy a szupererő paraméter értékét ne legyen kötelező megadni, alapértéke legyen 50!
1 2 3 4 |
|
Objektumok létrehozása¶
A példányosítás során az osztályból objektumpéldányt készítünk. Tehát az általános formai leírásunknak (ami az osztály) egy konkrét példányát gyártjuk le.
A példányosítás során meghívjuk a példányosítani kívánt osztály konstruktorát, amelynek rendre átadjuk a szükséges paramétereket (az első, self
paramétert nem adjuk át).
A példányosítás szintaxisa (a szögletes zárójelek közötti részek elhagyhatók):
1 |
|
Példa: Példányosítsuk a Szuperhos
osztályunkat!
1 2 3 4 5 6 7 |
|
Kimenet
-- Szuperhős létrehozva. --
Láthatóságok, getterek, setterek, property-k¶
Javában az adattagok és metódusok elérhetőségét különböző láthatósági módosítószavakkal tudtuk megadni (public
, protected
, private
, "package private" láthatóságok).
Pythonban nincsenek a láthatóság szabályozására szolgáló módosítószavak.
Konvenció alapján az adattag neve előtti egyszeres alulvonás azt jelzi, hogy az adattag nem publikus használatra van szánva ("private adattag"). Viszont ettől az adattag kívülről továbbra is elérhető lesz!
Példa: Jelezzük, hogy a Szuperhos
osztály adattagjait nem publikus használatra szánjuk!
1 2 3 4 |
|
Pythonban is készíthetünk az adattagokhoz hagyományos getter, illetve setter metódusokat.
Emlékeztetőül: a getter az adattagok értékének lekérdezésére, míg a setter az adattagok értékének beállítására szolgáló metódus. Ezeket nem publikus adattagok esetén használjuk.
Példa: Írjunk hagyományos gettert és settert a Szuperhos
osztály _szuperero
adattagjához!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Kimenet
100
Pythonban viszont a fenti szintaxis ritkán használatos. Ehelyett általában úgynevezett property-ket szoktunk használni getterek és setterek megvalósítására.
A get property szintaxisa:
1 2 3 |
|
A set property szintaxisa:
1 2 3 |
|
Példa: Cseréljük le a Szuperhos
osztályban a _szuperero
adattaghoz készített hagyományos gettert és settert property-kre! Figyeljük meg, hogy mennyivel egyszerűbb a property-k használata az osztály példányosítása után a hagyományos getter/setter függvényekhez képest!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Kimenet
100
Figyelem
Fontos, hogy a property és az adattag neve mindig eltérő legyen, mert különben végtelen rekurzióba futunk! A fenti példában a get és set property-k neve szuperero
(alulvonás nélkül), az adattag neve pedig ettől eltérő módon _szuperero
(alulvonással).
Feladat
A fenti mintájára készítsünk get és set property-t a _nev
adattaghoz is!
Objektumok kiíratása¶
Ha Pythonban a print()
függvénnyel kiíratunk egy objektumot, akkor valami ehhez hasonlót kapunk a konzolon: <_ _main_ _.OsztalyNeve object at 0x012B08D0>
.
Hát, ez közel sem szép. Szerencsére ezen lehetőségünk van szépíteni, ha az osztályon belül felüldefiniáljuk az __str__
metódust. Ez a metódus az objektum szöveggé alakítását valósítja meg (mint Javában a toString()
). Visszatérési értéke egy string, ezt írjuk felül.
1 2 3 4 5 |
|
Példa: Írjuk meg a Szuperhos
osztályban a szöveggé alakítást megvalósító metódust! A metódus írja ki az adattagok értékét!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Kimenet
Thor egy szuperhős, akinek szuperereje 70
Operator overloading¶
Az operator overloading segítségével kiterjeszthetjük a megszokott operátoraink működését.
Például a +
(plusz) operátort Pythonban használhatjuk két egész szám összeadására, illetve két string összefűzésére is. Ez azért lehetséges, mert a +
operátor ki van terjesztve az int
és az str
osztályokban egyaránt. Amikor egy operátor különböző osztályok példányaira használva másként viselkedik, operator overloading-nak nevezzük.
Pythonban a saját osztályainkban is lehetőségünk van bizonyos operátorok működését felüldefiniálnunk, ha felülírjuk a nekik megfelelő metódus működését.
Néhány speciális metódus, és az operátorok, amelyeket felüldefiniálhatunk vele:
Operator overload függvény | A függvényt meghívó kifejezés |
---|---|
__eq__ (egyenlőség) |
obj1 == obj2 |
__ne__ (nem egyenlőség) |
obj1 != obj2 |
__add__ (összeadás) |
obj1 + obj2 |
__sub__ (kivonás) |
obj1 - obj2 |
__iadd__ (megnövelés) |
obj1 += obj2 |
__isub__ (csökkentés) |
obj1 -= obj2 |
__lt__ (kisebb, mint) |
obj1 < obj2 |
__gt__ (nagyobb, mint) |
obj1 > obj2 |
__le__ (kisebb vagy egyenlő) |
obj1 <= obj2 |
__ge__ (nagyobb vagy egyenlő) |
obj1 >= obj2 |
Példa: Definiáljuk felül az ==
és +
operátorok működését a Szuperhos
osztályban!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Kimenet
True Megahős egy szuperhős, akinek szuperereje 150
Típusellenőrzés¶
Mivel a Python nem fordított nyelv, így statikus típusellenőrzés nincs benne. Ez aggasztó lehet, ha szeretnénk ellenőrizni, hogy a metódusunk egy bizonyos típusú paramétert kapott-e (például egy Szuperhos
objektumot).
Sajnos ezt csak dinamikusan, futásidőben tudjuk ellenőrizni, az isinstance(obj, type)
függvénnyel. A függvény pontosan akkor ad vissza igazat, ha az obj
objektum type
típusú.
Példa: Az __add__
metódus utasításait csak Szuperhos
típusú paraméter esetén hajtsuk végre! Eltérő típus esetén írassunk ki hibaüzenetet!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Az isinstance()
függvényt beépített típusokra is használhatjuk.
1 2 |
|
Kimenet
True False
A Szuperhos
osztály befejezése¶
Feladat
A szuperhősöknek legyen egy kepessegek
adattagja is, ami kezdetben egy üres lista! Definiáljuk felül a +=
operátort, ami a paraméterül kapott értéket beszúrja a kepessegek
lista végére, amennyiben az szöveges típusú!
A végleges kódunk
Az így kapott, végleges kódunk:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
|
A fenti kód kimenete:
1 2 3 4 5 6 7 |
|
Feladatok¶
Az anyagrészhez tartozó gyakorló feladatsor elérhető itt (a feladatsor megoldásához a következő leckében tárgyalt kivételkezelés ismerete is szükséges).