A Python típusosságának négy fő jellemzője: erős, dinamikus, objektumorientált és „kacsatípusos”.
A Python erősen típusos[]
Az erős típusosság fogalma az irodalomban nem egységes. A Python abban az értelemben erősen típusos, hogy kerüli az implicit típuskonverziókat, és rákényszeríti a programozót, hogy ő maga végezze el ezt a munkát. A hármas verzió egyik célja ennek a szigorúságnak az erősítése; így például még a „text”-nek nevezett Unicode-stringek és a „data”-nak nevezett, 8 bites karakterekből álló láncok konkatenálását sem engedi meg explicit típuskonverzió nélkül.
A típuskeverés – akár értékadásban, akár feltételvizsgálatban – futásidejű hibát okoz, amely kivételként kezelhető (lásd a példát a következő szakaszban). Valószínűbb azonban, hogy a hibaüzenet programozási hibát jelez, és inkább az okát kell átgondolni.
A Python dinamikusan tipizál[]
A dinamikus típusosság azt jelenti, hogy nem a változónak, hanem az értéknek van típusa, amit az értelmező futásidőben állapít meg. Nem kell előre deklarálni a felhasznált változók típusát, mint a Pascalban vagy a C-ben. Ez nagyobb rugalmasságot tesz lehetővé, de nagyobb fegyelmet is igényel. A szigorú típusosságnak köszönhetően azonban hamar a körmünkre koppint az értelmező, ha összekeverünk valamit.
Az alábbi példában az a változó előbb egész értéket kap, amihez hozzá tudunk adni hármat, majd string értéket, amitől megváltozik a típusa. Ha most próbáljuk elvégezni az összeadást, TypeError
kivételt kapunk. (A parancssor egyúttal számológépként is működik, tetszőleges kifejezést beírva megkapjuk az értékét, ezért a print()
függvény használata itt mellőzhető. Ne lepődjünk meg a megváltozott idézőjelen, a Python egyformán felismeri mind a kettőt.)
>>> a=5 >>> a+3 8 >>> a="5" >>> a '5' >>> a+3 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: cannot concatenate 'str' and 'int' objects
Ezután gépeljük be a parancssori promptnál az alábbi kivételkezelő kódot. Úgy írhatunk, mintha programot írnánk, figyelve a behúzásokra. A prompt a kódbeírást érzékelve megváltozik ...
-ra. Az utolsó sorban enterrel jelezzük, hogy befejeztük a bevitelt, mire megkapjuk a helyes eredményt, immáron stringként.
>>> try: ... a+3 ... except TypeError: ... a+"3" ... '53'
Sőt, akár az alábbi mókát is megengedhetjük magunknak:
>>> b="4" >>> c=7 >>> a+c*b '54444444'
Az a+c*b
kifejezésről tehát nem tudjuk megmondani, hogy összeadást vagy konkatenációt fejez-e ki, amíg nem ismerjük a változók aktuális típusát. Sőt, mivel a függvényparaméterek típusa is ugyanilyen dinamikus, még az alábbi függvény is az átadott paraméterek típusától függően viselkedik:
>>> def valami (a,b,c): ... return(a+c*b) ... >>> a="5" >>> b="4" >>> c=7 >>> valami(a,b,c) '54444444' >>> b=3 >>> c="9" >>> valami(a,b,c) '5999' >>> a=2 >>> c=7 >>> valami(a,b,c) 23
Ez talán egy kicsivel nagyobb rugalmasság, mint amit kezdő tanítványoknak szeretnénk nyújtani, de hamar meg lehet szokni, és – főleg, ha beszédes változónevekkel kombináljuk – nem akadálya a gondolati tisztaságnak és a strukturált programozásnak. Másrészt a dinamikus típusosság úgy tesz lehetővé memóriafoglalást a futásidőben, hogy feleslegessé válik a kezdő C- és C++-programozók életét megkeserítő mutatók használata.
Ugyanez a furcsaság gondot okozhat az adatbevitelben (akár a billentyűzetről, akár file-ból), ha nem figyelünk. Mivel az adatbevitel nem kötődik előre deklarált típushoz – sőt, mint a példa mutatja, még változóhoz sem feltétlenül! –, ezért a típusa sem magától értetődő. (Természetesen az alábbi tömör írásmódot csak akkor használhatjuk, ha nem akarjuk tárolni a beolvasott értéket. A C-stílusú, „röptében” történő értékadást a zárójelen belül a Python szándékosan nem engedi.)
>>> print('A háromszorosa:',3*input('Kérem a számot: ')) Kérem a számot: 7 A háromszorosa: 777
Nem nehéz rájönni, mi történt: az értelmező szövegként kezeli a bevitt adatot. Akár rejtvényként is feladhatjuk tanítványainknak a magyarázatot. Explicit kiírással is meggyőződhetünk róla:
>>> b=input('A szám: ') A szám: 5 >>> b '5'
A megoldás mind a billentyűzetről, mind a lemezről beolvasott számok esetében az int() konvertálófüggvény használata:
>>> print('A háromszorosa:',3*int(input('Kérem a számot: '))) Kérem a számot: 7 A háromszorosa: 21
Vigyáznunk kell azonban, mert az int() a nem numerikus adatoktól rögtön megadja magát!
>>> print('A háromszorosa:',3*int(input('Kérem a számot: '))) Kérem a számot: lajos Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for int() with base 10: 'lajos'
Ez a hiba könnyen kezelhető, azonban ez már a kivételkezelésről szóló szócikk témája.
A Python típusai egyúttal osztályok is[]
A Verziók felismerése és átalakítása szócikkben azt láthatjuk a képeken, hogy a type() függvény a 2.5 verzióban a „type”, a 3.1 verzióban a „class” szót adja vissza a változó típusa előtt. Minden típus egyúttal osztály is. A kezdő programozónak nem kell ezzel törődnie, tehát leérettségizhet az objektumok ismerete nélkül is.
A típusok ilyetén kezelése két fő előnnyel jár:
- Az egyes típusokhoz kényelmesen használható beépített metódusok tartozhatnak. Lásd a példát a Paradigmák cikkben.
- A beépített típusokból kedvünk szerint hozhatunk létre származtatott típusokat, amelyek öröklik a szülőtípus tulajdonságait és metódusait. Részletesen, példával lásd Guido van Rossum cikkében:
Duck typing[]
Megírandó, addig lásd itt.
Ez a szócikk forráskódot tartalmaz, amely egy WikiMedia-kiegészítés segítségével olyan színesen jeleníthető meg, mint például ebben a Wikipédia-cikkben. A kiegészítést a Wikia-stáb ígérete szerint 2010 végéig frissítik, addig türelmet kérünk a fapados kinézet miatt.