Az imént említett while utasítás mellett a Python ismeri a más nyelvekben szereplő leggyakoribb vezérlő utasításokat is - némi változtatással.
Talán a legjobban ismert utasítástípus az if utasítás. Példa:
>>> x = int(raw_input("Írjon egy számot: "))
>>> if x < 0:
... x = 0
... print 'Negatív, lecseréltem nullára'
... elif x == 0:
... print 'Nulla'
... elif x == 1:
... print 'Egy'
... else:
... print 'Egynél több.'
...
Hiányozhat, de lehet egy vagy akár egynél több elif rész, a else rész szintén elmaradhat. Az `elif' kulcsszó - amely az `else if' rövidítése - hasznos a felesleges behúzások elkerülésésre. Egy if ... elif ... elif ... sor helyettesíti a más nyelvekben található switch és case utasításokat.
A for utasítás különbözik attól, amely a C-ben és a Pascalban található. Ahelyett, hogy mindíg egy számtani sorozattal dolgozna (mint a Pascalban), vagy hogy megadná a lehetőséget a felhasználónak, hogy saját maga határozza meg mind az iterációs lépést, mind a kilépési feltételt (ahogy a C-ben van) a Python for utasítása végighalad a sorozat (pl. szövegek listája) összes elemén olyan sorrendben, ahogy a listában szerepelnek. Például:
>>> # Megmérjük a szavak hosszát: ... a = ['cat', 'window', 'defenestrate'] >>> for x in a: ... print x, len(x) ... cat 3 window 6 defenestrate 12
Nem biztonságos dolog megváltoztatni a sorozatot, amelyen ciklussal végighaladunk (ez csak megváltoztatható sorozattal, például listával történhet meg). Ha mégis szükséges megváltoztatnod a listát, akkor a másolatát használd a for ciklusban. A szelet (slice) jelölési móddal ezt kényelmesen megteheted:
>>> for x in a[:]: # egy másolatot csinál az eredeti listáról ... if len(x) > 6: a.insert(0, x) ... >>> a ['defenestrate', 'cat', 'window', 'defenestrate']
Ha egy számsorozaton kell végighaladnunk, a range() beépített függvény lehet szolgálatunkra. Ez egy számtani sorozatot állít elő lista formában, pl.:
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
A megadott végpont sohasem része a listának; range(10) 10 elemű
listát hoz létre, pontosan egy tízelemű sorozat indexeit. Lehetőség van
rá, hogy a sorozat más számmal kezdődjön, vagy hogy más lépésközt adjunk
meg (akár negatívat is):
>>> range(5, 10) [5, 6, 7, 8, 9] >>> range(0, 10, 3) [0, 3, 6, 9] >>> range(-10, -100, -30) [-10, -40, -70]
Ha egy sorozat indexein akarunk végighaladni, használjuk a range() és len() függvényeket a következőképpen:
>>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for i in range(len(a)): ... print i, a[i] ... 0 Mary 1 had 2 a 3 little 4 lamb
A break utasítás - ahogy a C-ben is - a break-et tartalmazó legmélyebb for vagy while ciklusból ugrik ki.
A continue utasítás - ez is a C-ből származik - a ciklus további utasításait átugorva a következő elemre ugrik (és elkezdi a következő ciklus-hurkot).
A ciklus-szervező utasításoknak lehet egy else águk. Ez akkor
hajtódik végre, ha a ciklus végighaladt a listán (for esetén),
illetve ha a feltétel hamissá vált (when esetén), de nem
hajtódik végre, ha a ciklust a break utasítással szakítottuk
meg. Ezt a következő példával szemléltetjük, amely a prímszámokat keresi meg:
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print n, 'felbontható:', x, '*', n/x ... break ... else: ... print n, 'prímszám.' ... 2 prímszám. 3 prímszám. 4 felbontható: 2 * 2 5 prímszám. 6 felbontható: 2 * 3 7 prímszám. 8 felbontható: 2 * 4 9 felbontható: 3 * 3
A pass utasítás nem csinál semmit. Akkor használható, ha szintaktikailag szükség van egy utasításra, de a programban nem kell semmit sem csinálni. Például:
>>> while 1: ... pass # Elfoglalt - billentyűzetről érkező megszakításra vár. ...
Létrehozhatunk egy függvényt, amely egy megadott értékig írja ki a Fibonacci-sorozatot:
>>> def fib(n): # Kiír egy Fibonacci-sorozatot n-ig ... "Kiír egy Fibonacci-sorozatot n-ig." ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b ... >>> # Hívjuk meg a függvényt amit létrehoztunk: ... fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
A def kulcsszó a függvény definícióját jelzi. Ezt egy függvénynévnek, majd zárójelben a paraméterek listájának kell követnie. Az utasítások - amelyek a definíció testét alkotják - a következő sorban kezdődnek, és behúzással kell kezdeni azokat. A függvény testének első utasítása lehet egy szöveges 'emberi mondat' is; ez a karakterlánc a függvény dokumentációs karakterlánca, angolul röviden docstring.
Vannak eszközök, amelyek a docstring-et használják ahhoz, hogy az online vagy a nyomtatott dokumentációt elkészítsék, vagy hogy a felhasználót segítsék a kódban történő interaktív böngészéshez. Bevált gyakorlat, hogy a docstringet beleírjuk a kódba, kérünk téged hogy te is szokjál rá.
A függvény végrehajtása egy új szimbólum-táblázatot hoz létre a függvény helyi változói számára. Pontosabban: minden értékadás a függvényben a helyi szimbólum-táblázatban tárolódik; a változókra való hivatkozások esetén először a Python helyi szimbólum-táblázatban, aztán a globális szimbólum-táblázatban, végül a belső (built-in) nevek közt keresgél. Így globális változóknak nem adhatunk közvetlenül értéket egy függvényben (hacsak nem nevezzük meg egy global utasításban), jóllehet hivatkozhatunk rá.
Ford.: Ez a kód a fenti leírással ellentétben a 'gyumolcsok' függvényen kívüli változót módosítani tudja. A 'penztarcaban' valtozot olvasni tudjuk, de ha ertekadassal probalkozunk, az olvasast is hibanak jelzi az ertelmezo:
gyumolcsok = ["alma"]
penztarcaban = 22
def kosar_kiirasa():
print gyumolcsok
gyumolcsok.append('barack')
print gyumolcsok
# erdekes: ha csak ez a print sor van, es a try-ban nem adunk
# erteket, akkor mukodik.
# ha adunk erteket, hibasnak jeloli ezt a sort is.
print penztarcaban, "Ft"
try:
# penztarcaban = 33
print penztarcaban, "Ft - try blokkbol, ertekadas kiprobalasnal"
pass
except:
print "a penztarcaban valtozot nem tudtam modositani"
kosar_kiirasa()
print "kosar kiirasa utan: ", gyumolcsok
A függvényhívás aktuális paraméterei bekerülnek a hívott függvény helyi szimbólum-táblázatába amikor azt meghívjuk, így az argumentumok mindig értékeket adnak át. (ahol az érték mindig az objektumra történő hivatkozás, nem az objektum értéke). 4.1Ha a függvény egy másik függvényt hív, akkor az új híváshoz egy új helyi szimbólumtábla jön létre.
A függvénydefiníció a függvény nevét beírja az aktuális szimbólumtáblába. A függvénynév értékének van egy típusa, amelyet a fordító a felhasználó által definiált függvényként ismer fel. Ezt az értéket átadhatjuk egy másik változónak, amely ekkor szintén függvényként használható. Ez egy általános átnevezési eljárás:
>>> fib <function fib at 10042ed0> >>> f = fib >>> f(100) 1 1 2 3 5 8 13 21 34 55 89
Kifogásolhatja bárki, hogy a fib nem függvény, hanem eljárás. A
Pythonban - ahogy a C-ben is - az eljárások olyan függvények, amelyek nem
adnak vissza értéket.
Gyakorlatilag egy nagyon különös értéket adnak vissza,
ez az érték a None - ez egy belső (built-in) név. A
None érték kiírását általában elnyomja az értelmező,
kivéve ha csak ezt az értéket kell kiírnia.
Erről meggyőződhetünk, ha akarunk:
>>> print fib(0) None
Könnyen írhatunk olyan függvényt, amely visszatér a Fibonacci-sorozat értékeit tartalmazó listával ahelyett, hogy kiíratná azokat.
>>> def fib2(n): # Visszaadja a Fibonacci-sorozatot n-ig ... "A Fibonacci-sorozat n-nél kisebb elemeit adja vissza egy listában." ... eredmeny = [] ... a, b = 0, 1 ... while b < n: ... eredmeny.append(b) # lásd lejjebb ... a, b = b, a+b ... return eredmeny ... >>> f100 = fib2(100) # hívjuk meg >>> f100 # írjuk ki az eredményt [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Ez a példa néhány új vonását mutatja a Pythonnak:
None értéket ad vissza.
Ha egy függvény lefutott, de te nem adtál meg return utasítást, a függvény None értékkel tér vissza.
eredmeny.append(b) utasítás meghívja az eredmeny-lista objektum egy
metódusát. A metódus egy olyan függvény, amely egy objektumhoz
,,tartozik'', obj.metódusnév alakban írjuk, ahol az obj
valamelyik objektum (lehet egy kifejezés), és a metódusnév egy olyan
metódus neve, amelyet az objektumtípus definiál. Különböző típusoknak
különböző metódusai vannak. Különböző típusoknak lehet azonos nevű
metódusa mindenféle kétértelműség veszélye nélkül. (Lehetőség van rá, hogy
definiáljunk saját objektumokat és metódusokat az osztályok
használatával, ahogy később azt látni fogjuk az oktatóban.)
A példában szereplő append() metódus a lista-objektumokra lett definiálva; ez hozzáad egy új elemet a lista végéhez. Ebben az esetben azonos az "eredmeny = eredmeny + [b]" alakkal, de ez sokkal hatékonyabb.
Lehetőségünk van függvényeket változó argumentummal definiálni. Ennek három formája van, amelyek variálhatók.
A leghasznosabb alak az, ha egy vagy több argumentumnak is meghatározott alapértéket adunk meg (azaz egy olyan értéket, amit ez az argumentum felvesz, ha nem adunk értéket neki. Ez így egy olyan függvényt hoz létre, amelyet kevesebb argumentummal is meghívhatunk, mint amennyivel definiáltuk:
def ask_ok(szoveg, probalkozasok=4, hibauzenet='igen vagy nem!'):
while 1:
ok = raw_input(szoveg)
if ok in ('i', 'igen','I','IGEN'): return 1
if ok in ('n', 'nem', 'N','NEM'): return 0
probalkozasok = probalkozasok - 1
if probalkozasok < 0: raise IOError, 'értelmetlen használat'
print hibauzenet
Ez a függvény ehhez hasonlóan hívható meg:
ask_ok('Valóban ki akarsz lépni?') vagy így:
ask_ok('Felülírhatom a fájlt?', 2).
Az előző program egyben példa az in kulcsszó használatára is. Így tesztelhetjük, hogy a sorozat vajon tartalmaz-e egy adott értéket, vagy nem.
Az alapértékeket a fordító akkor határozza meg, amikor
a függvény definíciójával először találkozik,
emiatt ezek kiszámítása csak egyszer történik meg!
(defining) Így például a következő program eredménye 5lesz:
i = 5
def f(arg=i):
print arg
i = 6
f()
Fontos figyelmeztetés: Az alapértékeket a fordító csak egyszer határozza meg! Emiatt különbség van, ha az alapérték megváltoztatható objektum, mint amilyen a lista, szótár vagy a legtöbb példányosodott osztály. Például az alábbi függvény összegyűjti az egymás utáni hívások során neki adott paramétereket:
def f(a, L=[]):
L.append(a)
return L
print f(1)
print f(2)
print f(3)
A program kimenete:
[1] [1, 2] [1, 2, 3]
Ha nem akarod az alapértékeket láthatóvá tenni az egymást követő hívások számára, akkor ehhez hasonlóan írd a függvényt:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
A függvényeket akár "kulcsszó = érték" formában megadott argumentumok használatával is meghívhatjuk. Például a következő függvény:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print "-- This parrot wouldn't", action,
print "if you put", voltage, "Volts through it."
print "-- Lovely plumage, the", type
print "-- It's", state, "!"
meghívható az összes alábbi módon:
parrot(1000)
parrot(action = 'VOOOOOM', voltage = 1000000)
parrot('a thousand', state = 'pushing up the daisies')
parrot('a million', 'bereft of life', 'jump')
de a következő hívások mind érvénytelenek:
parrot() # a kötelező argumentum hiányzik parrot(voltage=5.0, 'dead') # nem-kulcsszavas argumentum kulcsszavas után parrot(110, voltage=220) # kétszeres értékadás egy argumentumnak parrot(actor='John Cleese') # ismeretlen kulcsszó
Általában egy argumentumlistában néhány helyhez kötött argumentum után néhány kulcsszavas argumentumnak kell szerepelnie, ahol a kulcsszavakat a formális paraméterek közül kell választani. Nem lényeges, hogy egy formális paraméternek van-e alapértéke vagy nincs. Egy hívás során nem kaphat egy argumentum egynél több alkalommal értéket - helyhez kötött argumentumhoz tartozó formális paraméter nem használható kulcsszóként ugyanannál a hívásnál. Itt van egy példa, amely nem hajtódik végre emiatt a megkötés miatt:
>>> def function(a): ... pass ... >>> function(0, a=0) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: function() got multiple values for keyword argument 'a'
Ha van egy **név alakú formális paraméter utolsóként, akkor egy
ilyen nevű szótárban tárolódik az összes kulcsszavas argumentum, amelynek a
kulcsszava nem illeszkedik egyetlen formális paraméterre sem. Ez együtt
használható egy *név alakú formális paraméterrel (ez a következő
alszakaszban lesz leírva) amely belerakja az összes olyan nem-kulcsszavas
argumentumot, amely nincs benne a formális paraméterlistában, egy tupléba.
(A *név-nek mindíg a **név előtt
kell lennie.)
Például, ha egy ilyen függvényt definiálunk:
def sajtuzlet(sajtfajta, *argumentumok, **kulcsszavak):
print "-- Van Önöknél néhány", sajtfajta, '?'
print "-- Sajnálom, teljesen kifogytunk a", sajtfajta+'ból'
for arg in argumentumok: print arg
print '-'*40
for kw in kulcsszavak.keys(): print kw, ':', kulcsszavak[kw]
Ez meghívható így is:
sajtuzlet('Pálpusztai', "Ez nagyon büdös, uram.",
"Ez nagyon, NAGYON büdös, uram.",
vevo='Sajti János',
boltos='Pálinkás Mihály',
helyszin='Sajtbolt')
és természetesen ezt fogja kiírni:
-- Van Önöknél néhány Pálpusztai ? -- Sajnálom, teljesen kifogytunk a Pálpusztaiból Ez nagyon büdös, uram. Ez nagyon, NAGYON büdös, uram. ---------------------------------------- vevo : Sajti János boltos : Pálinkás Mihály helyszin : Sajtbolt
Megjegyzendő, hogy a kulcsszavak nevű szótár tartalmának kinyomtatása
előtt hívtuk meg a kulcsszó-argumentum neveinek listájához tartozó
sort() eljárást; ha nem ezt tesszük, akkor az argumentumok listázási
sorrendje határozatlan.
Végül itt a legritkábban használt lehetőség, amikor egy függvénynek tetszőleges számú argumentuma lehet. Ezeket az argumentumokat egy tupléba helyezi el a Python. A változó számosságú argumentum előtt akárhány (akár egy sem) egyszerű argumentum is előfordulhat.
def fprintf(file, format, *args):
file.write(format % args)
Ennek fordítottja történik, ha listába vagy tupléba becsomagolt argumentumokat
ki kellene csomagolni olyan függvény meghívásához, amely elkülönített,
helyhez-kötött változókat vár.
Például a beépített range() függvény egymástól elkülönítve várja a
start és stop értékeket. Ha ezek nem egymástól elválasztva
állnak rendelkezésre, akkor a
függvényhívásban a * műveletjelet tegyük
az összetett-típusú változó neve elé, ez kicsomagolja a listából vagy
tupléből az adatokat.
>>> range(3, 6) # normális függvényhívás, különálló paraméterekkel [3, 4, 5] >>> args = [3, 6] >>> range(*args) # listából kicsomagolt paraméterekkel történő függvényhívás [3, 4, 5]
Többek kívánságára néhány olyan vonás került a Pythonba, amelyek a funkcionális programozási nyelvekben és a Lisp-ben is megtalálhatóak. A lambda kulcsszóval rövid névtelen függvényeket lehet létrehozni. Íme egy függvény, amely a két argumentumának összegével tér vissza: "lambda a, b: a+b". A lambda formákat mindenhol használhatjuk, ahol függvény objektumok szerepelhetnek.
Szintaktikailag egyetlen kifejezés szerepelhet bennük. Általánosságban tekintve 'hab' a normális függvények 'tortáján'. Beágyazott függvénydefinícióként látja az őt meghívó környezet minden változóját.
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) # make_incrementor magyarul kb.: csinálj növelő-t >>> f(0) 42 >>> f(1) 43
A dokumentációs szövegek tartalmával és formájával kapcsolatban egy kialakult és bevált szokásról beszélhetünk.
Az első sor mindig az objektum céljának rövid, tömör összegzése. Rövidsége miatt nem kell tartalmaznia az objektum nevét vagy típusát, hiszen ezek az adatok más úton is kinyerhetők (kivéve, ha az objektum neve a függvény működését leíró ige). A szöveg nagybetűvel kezdődik és ponttal végződik.
Ha a dokumentációs szöveg (docstring) több sorból áll, a második
sor üres lesz - ezzel vizuálisan elkülönítjük a fejrészt/összegzést
a leírás további részétől. Az üres sort egy vagy több rész követheti,
ahol leírjuk az objektum hívásának módját, a mellékhatásokat stb.
Maga a Python értelmező nem szedi le a helyközöket a többsoros beégetett
szöveből - ha ezek kiszűrése szükséges, akkor ehhez külön szövegfeldolgozó
progit kellene használni. Ezt a problémát a következő konvenció használatával kezeljük.
Az első sor után a legelső nem üres sorban megjelenő szöveg behúzási
távolsága határozza meg az egész dokumentációs szöveg behúzását.
(A legelső sort azért nem hassználjuk erre a célra, mert a szöveg első betűje
általában szorosan követi a karakterláncot nyitó macskakörmöt, ennek eltolása nem
lenne nyilvánvaló dolog.) A docstring - fejrészt követő minden első sorának
elejéről levágunk pont ennyi helyközt. Ha ennél kevesebb helyközt tartalmaz valamely
sor - bár ilyennek nem kéne lennie - csak a helyközök törlődnek, karakter nem vész el.
A behúzások egyenlőségét ajánlott mindig a tabulátorokat kibontva ellenőrizni
(általában 1 tabulátort 8 helyközzel helyettesítünk).
Itt van egy példa a többsoros docstring-re:
>>> def fuggvenyem():
... """Nem csinál semmit, de ez dokumentálva van.
...
... Valóban nem csinál semmit.
... """
... pass
...
>>> print fuggvenyem.__doc__
Nem csinál semmit, de ez dokumentálva van.
Valóban nem csinál semmit.