A Python programozási nyelv

Objektum-orientált programozás

Osztályok, objektumok

A Python osztálymechanizmusának tervezésénél törekedtek a minimális szintaktikai és szemantikai újdonságok bevezetésére. Tulajdonképpen egyfajta keveréke a C++ és a Modula-3 osztálymechanizmusának. Lehetőség van többszörös öröklődésre, a származtatott osztály átdefiniálhatja az ősosztálya (inak) metódusait, egy metódus hívhatja az ősosztály metódusát ugyanazon a néven. Az objektumok tartalmazhatnak privát adatokat. A dupla `_'-sal kezdődő tagokat a parser a szintaktikai előfordulástól függetlenül `_classname__member'-re cseréli ki, ahol `classname' az aktuális osztály neve, a bevezető `_'-ok levágása után.

C++ terminológiával élve minden osztálymember (az adatmembereket is beleértve) publikus, és minden memberfüggvény virtuális. Modula-3-hoz hasonlóan nincs lehetőség röviden hivatkozni egy objektum memberére. Az osztályok maguk is objektumok - valójában a Pythonban minden adattípus objektum. (Azonban nem minden objektumnak van osztálya! Pl.: file, integer, lista,...) Az osztályobjektumokon kétfajta műveletet végezhetünk. Az egyik művelet az attribútumhivatkozások létrehozása, a másik pedig az osztály egy példányának létrehozása. De beépített típusokat nem bővíthet a felhasználó (nem örökölhet tőlük). A legtöbb beépített operátor újrahasználható osztálymembernek.

Ugyanarra az objektumra hivatkozhatunk több néven (lehet alias neveket csinálni).

Osztálydefiníció:

class ClassName: 'class_docstring' statement-1 ... statement-N

Pélául:

class MyClass: "Egy egyszerű példa osztály" i = 42 def f(x): return 'hello world!'

Az vezérlésnek rá kell futnia az osztálydefinícióra, mielőtt hatása lenne, így akár egy if-ágban is lehet osztálydefiníció! Az osztálydefiníció végén automatikusan létrejön az osztály-objektum. Példányosítani úgy tudunk, mintha egy paraméter nélküli függvényt hívnánk meg ( x = MyClass() ).

Osztályattribútumok

Adatattribútumok

Az adatattribútumokra, mint lokális változókra, él az a szabály, hogy nem kell őket előre definiálni: első használatukkor jönnek létre. Példa:

x = MyClass
x.counter = 1
while x.counter < 10:
    x.counter = x.counter * 2
print x.counter
del x.counter

Ez a kis példa 16-ot ír ki (nem a legegyszerűbb módon :), és semmilyen nyoma nem marad az osztályban, hisz a del utasítással töröltük.

Metódusattributumok

Az osztályok metódusait az osztályok példányaiból hívhatjuk meg. A Python a kötési mechanizmuson keresztül korlátozza a metódushívásokat az osztálypéldányra. Egy metódus kötöttnek minősül, ha a példány létezik, és kötés nélküli, ha a példány nem létezik Kötés nélküli metódust úgy hívhatunk meg, hogy explicit módon adjuk át a példányt.

x.f nem ugyanaz, mint MyClass.f! x.f egy metódus objektum, nem függvényobjektum.

x.f() - ki fogja írni: hello world. Ugyanis az objektum, mint első argumentum átadódik a függvénynek, azaz x.f() ekvivalens MyClass.f(x) -el.

További megjegyzések
class Complex: def __init__(self, realpart, imagpart): self.r = realpart self.i = imagpart x = Complex(3.0,-4.5)

Öröklődés

class DerivedClassName([modulename.]Base)

A Base osztálynévnek láthatónak kell lennie a DervideClassName definíciójának helyén. Az ősosztály definíciójának feldolgozása előbb történik, mint a leszármazott osztályé, és a leszármazott osztály a saját attribútumain kívül csak annyi információt tárol hogy ki az őse. Ez a hivatkozások feloldásánál játszik fontos szerepet: ha a hivatkozott attribútum (adattag vagy metódus) nem található meg a leszármazott osztályban, akkor a keresés az ősosztálynál folytatódik. Ez a szabály rekurzívan folytatódik az ősosztály ősére is, és így tovább.

A leszármazott osztályok felüldefiniálhatják az ősosztályok attribútumait. Mivel a hivatkozások (függvényhívások) feloldása teljesen dinamikus, ezért könnyen előfordulhat, hogy az ősosztály egy olyan metódusa, amely hív egy másik szintén ősosztálybeli metódust, valójában a leszármazott osztály felüldefiniált metódusát hívja. Ez a jelenség jól ismert lehet a C++ programozók körében: ott ezt dinamikus összekapcsolásnak hívják, és az ilyen metódusokat virtual metódusoknak nevezik. C++ terminológiával tehát a Pythonban minden metódus virtuális.

A felüldefiniáló metódus legtöbbször kibővíteni szeretné az ősosztály metódusát, nem teljesen átírni azt. Természetesen erre is lehetőség van: a Base.methodname() metódushívással meghívhatjuk az ősosztály metódusát a felüldefiniáló metódus törzsében.

A Python rendelkezik két beépített függvénnyel, amely együttműködik az öröklődés fogalmával: az isinstance() és az issubclass() függvénnyel. Ezekről a függvényekről részletesebben a Speciális metódusok részben olvashat.

Többszörös öröklődés

class DerivedClassName([modulename.]Base1[,[[modulename.]Base2,...])

Régi stílusú osztályoknál az attribútum keresésre egyetlen szabály van: mélységi, balról jobbra. Tehát ha hivatkozás történik egy objektum attribútumra, akkor először az objektum táblájában keresi a végrehajtó az adott attribútumot. Ha az attribútumot nem találja ott, akkor Base1-ben keresi. Ha ott sem, akkor Base1 őseiben. Ezután ha még mindig nem találta, akkor Base2-ben kezdi el keresni hasonlóan, és így tovább.

Az új stílusú osztályoknál a metódushivatkozás feloldásának sorrendjét dinamikusan határozza meg a végrehajtó környezet. Azért, hogy a közös ősosztályokat ne kelljen többször vizsgálni, az algoritmus linearizálja a keresési sorrendet úgy, hogy az őszosztályok közötti balról-jobbra elv megmaradjon. Ez az eljárás garantálja, a többszörös öröklődési rendszer megbízható és konzisztens legyen.

Példák

Egyszerű példa osztályokra

Rekord vagy struct-szerű objektumot az alábbi módon lehet létrehozni:

class Dolgozo:
    pass        # ez egy űres osztálydefiníció
 
John = Dolgozo()
John.nev = 'John Cosinus'
John.osztaly = 'Matematikai reszleg'
John.fizetes = 42000
class os:      def __init__(self, nev="os"):              self.nev = nev      def print_nev(self): print "En", self.nev,"vagyok." class osbol_szarmaztatott(os):      def __init__(self, nev):              self.nev = nev      def print_nev(self): print "Te", self.nev,"vagy."      def os_meghivasa(self): os.print_nev(self)       nev_nelkul=os() nev_nelkul.print_nev() nevvel=os("leszarmazott") nevvel.print_nev() orokolt=osbol_szarmaztatott("masodik leszarmazott") orokolt.print_nev() orokolt.os_meghivasa() print s=raw_input('Nyomj meg egy billentyut!')

Példa saját változók használatára

class a:     def __init__(self):         print "hello"                    def __del__(self):         print "bye"         b=a() b=None print s=raw_input('Press any key!')

Becsomagolás

A becsomagolásra akkor van szükség, ha egy standard típus viselkedését kell leszármaztatnunk, mert a Python ezt a műveletet közvetlenül nem támogatja. A művelet elvégzéséhez előzőleg be kell csomagolnunk az adattípust mint egy osztálytagot egy osztályba. Ezt követően már használhatjuk ennek az osztálynak az objektumát, és a becsomagolt adattípust tetszésünk szerint megváltoztathatjuk.

Speciális metódusok

Speciális metódusok bármely osztályra (class) vonatkozólag

(s: self, o: más)

__init__(s,argumentumok)   objektum installálása
__del__(s)   meghívódik az objektum megszünésekor (értéke 0 lesz)
__repr__(s)     repr() és ´...´ konverziók
__str__(s)     str() és 'print' kifejezések
__cmp__(s, o)     <, ==, >, <=, <>, !=, >=, is [not] implementálásakor
__hash__(s)     hash() és dictionary operátorok
__getattr__(s, név)     meghívódik, ha az attribútum keresés nem találja <nev>- et.
__setattr__(s, név, érték)     meghívódik, ha attribútumnak adunk értéket.
(benne ne használjuk a "self.név = érték" kifejezést,használjuk a "self.__dict__[név] = érték")
__delattr__(s, név)     meghívódik, hogy töröljük a <név> attribútumot.
__call__(self, *argumentumok)     meghívódi, amikor egy példányt függvényként hívunk meg.

isinstance(ob1, ob2), ahol az első argumentum egy példányobjektum, a második pedig egy osztályobjektum vagy típusobjektum. Azt vizsgálja, hogy az ob1 az ob2 osztály egy példánya-e, vagy, hogy az ob1 típusa megegyezik-e az ob2 típusával.

issubclass(osztály1, osztály2): megvizsgálja, hogy az osztály1 az osztály2 alosztálya-e. Egy osztály a saját alosztályának tekinthető.

hasattr(obj, attr), ahol az első argumentum egy objektum, a második pedig egy karakterlánc. A függvény azt vizsgálja, hogy van-e az objektumnak egy vagy több olyan attribútuma, amelynek a neve azonos az átadott karakterlánccal.

Numerikus operátorok speciális metódusai

(s: self, o: más)
s+o = __add__(s,o)
s-o = __sub__(s,o)
s*o = __mul__(s,o)
s/o = __div__(s,o)
s%o = __mod__(s,o)
divmod(s,o) = __divmod__(s,o)
pow(s,o) = __pow__(s,o)
s&o = __and__(s,o)
s^o = __xor__(s,o)
s|o = __or__(s,o)
s<<o = __lshift__(s,o)
s>>o = __rshift__(s,o)
nonzero(s) = __nonzero__(s) (logikai teszteléskor használjuk)
-s = __neg__(s)
+s = __pos__(s)
abs(s) = __abs__(s)
~s = __invert__(s) (bit szerint)
int(s) = __int__(s)
long(s) = __long__(s)
float(s) = __float__(s)
oct(s) = __oct__(s)
hex(s) = __hex__(s)
coerce(s,o) = __coerce__(s,o)
A jobb oldali egyenlõségek minden bináris operátorra léteznek; azokat akkor hívjuk meg, amikor az osztály példánya az operátor jobb oldalán szerepel.
a + 3 hívása __add__(a, 3)
3 + a hívása __radd__(a, 3)

Szekvenciák és értéktáblák, általános mûveletek kiegészítés:

(s: self, i: index vagy kulcs )

len(s) = __len__(s) objektum hossza, >= 0.  0 hosszúság == false
s[i] = __getitem__(s,i) i indexû/kulcsú elem, 0-tól számítjuk.
Szekvenciák, általános metódusok, kiegészítés:
s[i]=v = __setitem__(s,i,v)
del s[i] = __delitem__(s,i)

s[i:j] = __getslice__(s,i,j)
s[i:j]=szekv. = __setslice__(s,i,j,szekv.)
del s[i:j] = __delslice__(s,i,j) == s[i:j] = []

Értéktáblák, általános metódusok, kiegészítés:

hash(s) = __hash__(s) - dictionary típusra hívatkozás hash értéke
s[k]=v = __setitem__(s,k,v)
del s[k] = __delitem__(s,k)

Speciális, tájékoztatást adó attribútumok néhány típusra vonatkozólag:

X.__dict__ dict (szótár), melyet objektumok írható attribútumainak tárolására használnak
I.__methods__ I metódusainak listája; sok beépített típusokra (built-in types) érvényes.
I.__members__ I adatattribútumainak listája; sok beépített típusra (built-in types) érvényes.
I.__class__ osztály (class) mely példányához tartozik I
C.__bases__ r/o attribútum, C osztály alaposztályaiból álló tuple típusú változó az eredménye.
M.__name__ r/o attribútum, az M nevét szolgáltatja sztring értékként

Elemek felderítésére állandósult kifejezések

dir(<modul>) a <modul> függvényeinek, változóinak listáját szolgáltatja
dir() az objektum kulcsszavait adja vissza, alapbeállítás a helyi érvényességi körre vonatkozik
X.__methods__ az X által támogatott metódusok listája(, ha létezik)
X.__members__ X adatattribútumait szolgáltatja
if __name__ == '__main__': main() meghívja a main() függvényt, ha a modult script-ként futtatjuk.
map(None, 1. lista, 2. lista, ...) a két listát összevonja
b = a[:] másolatot készít a szekvencia szerkezetérõl
_ interaktív módban a legutoljára kinyomtatott értéket jelöli.