Subsections


4. További vezérlő utasítások

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.


4.1 Az if utasítás

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.


4.2 A for utasítás

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']


4.3 A range() függvény

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


4.4 A break és a continue utasítások, az else ág a ciklusokban

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


4.5 A pass utasítás

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.
...


4.6 Függvények definiálása

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:


4.7 Még több tudnivaló a függvények definiálásáról

Lehetőségünk van függvényeket változó argumentummal definiálni. Ennek három formája van, amelyek variálhatók.


4.7.1 Alapértelmezett (default) argumentumértékek

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


4.7.2 Kulcsszavas argumentumok

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.


4.7.3 Tetszőleges hosszúságú argumentumlisták

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)


4.7.4 Argumentumlista kicsomagolása

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]


4.7.5 Lambda formák

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


4.7.6 A dokumentációs szövegek

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.



Footnotes

... értéke).4.1
Pontosabban a objektumra történő hivatkozással történő meghívás jobb elnevezés lenne erre, mert ha egy megváltoztatható objektumot adunk át, a hívó minden változást látni fog, amit a hívott függvény csinál vele (pl. ha elemet szúr a listába).
See About this document... for information on suggesting changes.