A Python programozási nyelv

Sablonok

A Pythonban nincsen nyelv által biztosított megoldás a sablonokra.

Mivel azonban a Python gyengén típusos nyelv, így az általános célú, generikus használhatóságú programkódok készítése igen elterjedt. Elősegíti az ilyen kódok írását továbbá az is, hogy a Python széleskörű osztály-tesztreszabást teszt lehetővé: könnyen írhatunk osztályunkhoz összehasonlítás operátort, vagy iterátor-támogatási műveletet. Az osztály-testreszabás lehetőségeiről az Objektum-orientált programozás fejezet "Speciális metódusok" részében olvashat. Fontos azonban megjegyezni, hogy ugyan a gyenge típusosság adta lehetőségek szinte végtelenek, ugyanakkor az e fajta generikusság nem ellenőrzött. Nem tehetünk például megszorításokat a paraméterek típusára, vagy a függvények használatára, és ez gyakran futásidejű hibához vezethet, ezáltal csökken a program megbízhatósága.

Egy-két példa a gyenge típusosság kihasználására

Készítsünk egy rendezett lista adatszerkezetet! A listába be lehet szúrni elemet, törölni lehet elemet, le lehet kérdezni a hosszát a len() beépített függvény segítségével, valamint ki lehet olvasni az első és utolsó elemét.

class OrderedList(object):
#listaval reprezentaljuk
lista = []

#inicializalo metodus
def __init__(self, iterable=None):
if iterable != None:
for item in iterable:
self.lista.append(item)
self.lista.sort()

def insert(self, element):
self.lista.append(element)
self.lista.sort()

def remove(self, element):
self.lista.remove(element)
self.lista.sort()

def __len__(self):
return len(self.lista)

def first(self):
return self.lista[0]

def last(self):
return self.lista[len(self.lista) - 1]

def __iter__(self):
return iter(self.lista)

def __str__(self):
return str(self.lista)
Most pedig próbáljuk ki a típusunkat!
>>> l_int = OrderedList([2,4,5,21,7,45])
>>> print l_int
[2,4,5,7,21,45]
>>> l_int.remove(2)
>>> l_int.first()
4
>>> l_string = OrderedList()
>>> l_string.insert("korte")
>>> l_string.insert("alma")
>>> l_string.insert("barack")
>>> for gyumolcs in l_string:
... print gyumolcs
...
'alma'
'barack'
'korte'

Látható a példából, hogy az OrderedList egyaránt működik egész számokkal és stringekkel is.
Mi a buktatója akkor ennek a fajta generikusságnak?
A legnagyobb baj az, hogy nincs lehetőség megszorítások kötésére. Vegyük észre, hogy a rendezés a beépített sort() függvénnyel történik. Ahhoz viszont, hogy két, ugyanolyan típusú elemet összehasonlítsunk, a típusnak implementálnia kell az összehasonlító függvényt, függvényeket. Beépített típusoknál ez adott, de a felhasználó által definiált típusoknál viszont nem mindig, és ilyenkor az objectID alapján történik az összehasonlítás. Jó lenne valahogy megszorítani, hogy a rendezett listánkba csak olyan típusú elemeket lehetne beszúrni, amin értelmezve van az összehasonlítás művelet.
Továbbá figyeljük meg az inicializáló metódust: az egy iterált paramétert vár, és ha kapott paramétert, akkor bejárja for ciklussal azt. No de mi van akkor, ha a kapott paraméter nem iterálható? A válasz egyszerű: futásidejű hiba keletkezne.
Tehát mivel a nyelv szintjén nem lehet megszorításokat tenni, ezért nekünk, programozóknak kell a programkódból kitalálni, hogy milyen megszorítáokkal használhatjuk csak az adott programot. Nyilvánvaló, hogy ez nem mindig sikerül, ami megbízhatatlan programkódhoz vezet(het)...

Tegyük fel, hogy a programunk ember entitásokkal dolgozik: feldolgozza az adataikat, statisztikákat számol, stb. Ilyenkor készítenénk egy 'Ember' osztályt, magasság, testsúly, nem:

class Ember(object):
def __init__(self, nev, magassag, testsuly):
self.nev = nev self.magassag = magassag
self.testsuly = testsuly
Megpróbáljuk naívan úgy létrehozni a rendezett listát, hogy egyetlen embert adunk át neki paraméterként (azt akarjuk, hogy csak ő legyen benne kezdetben):
>>> elemer = Ember("Elemer", 175, 78)
>>> emberek = OrderedList(elemer)
Traceback (most recent call last):
emberek = OrderedList()
File <stdin>, line 1, in ?
for item in iterable:
TypeError: iteration over non-sequence
Tegyünk be embereket a rendezett listánkba, és nézzük meg, mi történik:
>>> emberek = OrderedList()
>>> elemer = Ember("Elemer", 175, 78)
>>> aladar = Ember("Aladar", 177, 79)
>>> karoly = Ember("Karoly", 189, 90)
>>> emberek.insert(elemer)
>>> emberek.insert(aladar)
>>> emberek.insert(karoly)
>>> for e in emberek:
... print e
...
Elemer
Aladar
Karoly
Látható, hogy nem rendezte sorba őket. Ez azért van, mert az Ember osztály nem definiálja az összehasonlítás műveletet, ezért a végrehajtó rendszer az objectID-t (memóriacím) használja az összehasonlításhoz. Implementáljuk az összehasonlítás műveletet az Ember osztályon, mint a név ABC szerinti sorba rendezését:
def __cmp__(self, other):
cmp(self.nev, other.nev)
Ekkor a várt eredményt kapjuk:
Aladar
Elemer
Karoly