Ügyességi játékok programozása
Pythonnal és Pygame-mel

Chapter 9: Függvények

9.1 Bevezető a függvényekhez

Videó: Miért használjunk függvényeket?

Függvényeket két okból használunk. Először is, ez könnyebbé teszi a kódunkat mind olvasni, mind megérteni. Másodsorban, lehetővé teszik, hogy a kódunkat többször is felhasználjuk, ne csak egyszer.

Képzelj el egy kódcsoportot, amik játékautókat vezérelnek. Mondjuk, a programozó szeretné, hogy a játékautó előre menjen. Ehhez, a következő parancsokat hajtatja végre:

turnOnMotor()
pauseOneSecond()
turnOffMotor()

Ha definiáljuk a függvényeket, akkor a program olvashatósága megnő és újra lehet használni, bármennyiszer.

def moveForward():
    turnOnMotor()
    pauseOneSecond()
    turnOffMotor()

Önmagában ez a kód nem fogja még előre mozgatni az autót. Még meg kell adnunk a számítógépnek, hogy hogyan tegye az előre mozgatást. Neked kell meghívnod a függvényt az aktuálisan futott kód szerint, hogy az autó elinduljon:

moveForward()

Ha van egy teljes könyvtárunk ilyen funkciókkal, akkor az autó mozgatása, mindössze így néz ki:

moveForward()
turnLeft()
moveForward()
moveForward()
turnRight()
moveForward()

Emlékezz arra, hogy a moveForward parancsnak három sora van. Minden ilyen parancs több sor kódot foglal magába. Ezeket a függvényeket használva, ismételhetjük a parancsokat akár anélkül, hogy az összes parancsot ismételtetnénk, amit magába foglal, így hozva létre kisebb programokat.

A függvénynevek nagyon fontosak. Ha a függvény nevek leíró jellegűek, akkor még egy nem-programozó is képes lesz megérteni a kód egy részét és valamiféle elképzelést kialakítani arról, hogy mit is csinál. A függvénynevekre ugyanazok a szabályok vonatkoznak, mint a változókra, és kisbetűvel kell, hogy kezdődjenek.

9.2 A függvények paraméterei

fig.function

A függvényeknek van paraméterük. Ezek arra jók, hogy megnöveljék a flexibilitását a függvénynek, megmondva neki azt, hogy mit cselekedjen. Például, egy függvény, amit moveForward() -nak hívnak, előre mozgat egy robotot egy másodpercre. De a függvényt meg lehet változtatni azzal, hogy adunk neki egy paramétert, ami azt határozza meg, hogy hány másodpercig. A példánál maradva, moveForward(3) előre fogja mozgatni 3 másodpercig, míg a moveForward(6) már hat másodpercig.

A robotot irányító függvényünk valahogy így néz ki:

def moveForward(time):
    turnOnMotor()
    for i in range(time):
        pauseOneSecond()
    turnOffMotor()

Itt van egy másik függvény, ami robot autó nélkül is elfut. Ez a függvény kiszámolja és kiírja egy gömb térfogatát:

def volumeSphere(radius):
    pi = 3.141592653589
    volume = (4 / 3) * pi * radius ** 3
    print("The volume is", volume)
Videó: Függvény létrehozása
A paraméterek akkor határozzák meg az értéket, amikor a függvényt meghívják, és nem amikor azt definiálják.

A függvény neve volumeSphere. Az adat, amit a függvénynek megadunk, egy új változóban fog tárolódni, amit radius-nak hívunk. Az eredmény, a térfogat ki lesz íratva a képernyőre. A radius. változónak nincs értéke még itt. Az újdonsült programozók sokszor vétenek, amikor értéket akarnak adni a függvény paramétereinek a létrehozásukkor, ez nem legális. A paramétereknek akkor adunk értéket, amikor a függvényt meghívjuk:

Ha meg akarod hívni a függvényt, tedd így:

volumeSphere(22)

A radius változó a függvényben 22-re van kezdetben állítva. A függvény kódja lefut egyszer és végrehajtja egyszer, amit kell.

Mi van akkor, ha több, mint egy értéket szeretnénk vizsgálni? Több paraméter is adható egy függvényhez, ha mindegyiket elválasztjuk vesszővel.

def volumeCylinder(radius, height):
    pi = 3.141592653589
    volume = pi * radius ** 2 * height
    print("The volume is", volume)

Ezt a függvény így hívhatjuk meg:

volumeCylinder(12, 3)

A paraméterek sorrendben hajtódnak végre, így a radius értéke 12 lesz, majd a height változó értéke kapja a 3-t.

Sajnos, ezek a példa függvények végesek. Miért? Ha valaki használni akarja a volumeCylinder függvényt, hogy megkapja a térfogatát hat hengernek, ez nem fog menni. Ez csak egy henger térfogatát írj ki. Nem lehetséges felhasználni a függvény eredményeit, és hat térfogatra számoltatni.

Ezt a problémát kiküszöbölhetjük a return paranccsal. Például:

def volumeCylinder(radius, height):
    pi = 3.141592653589
    volume = pi * radius ** 2 * height
    return volume

A return nem egy függvény, és nem kell zárójelet sem használnunk. Ne csinálj ilyet, hogy return(volume).

Mivel a return benne van a függvényben, ezért már később is felhasználhatjuk, akár hatszor is:

sixPackVolume = volumeCylinder(2.5, 5) * 6

Az érték, amit a volumeCylinder ad vissza, az egyetlenben végrehajtódik, és meghatszorozzuk.

Nagy a különbség a függvény közt, ami csak print-el, vagyis kiírat egy értéket, és aközött, amelyik visszaad(returns) egy értéket. Nézd meg a lenti kódot és próbáld ki:

#A függvény, ami kiírja az eredményt
def sumPrint(a, b):
    result = a + b
    print(result)

# A függvény, ami visszaadja az eredményt
def sumReturn(a, b):
    result = a+b
    return result

# Ez kiírja 4+4 eredményét
sumPrint(4, 4)

# Ez nem
sumReturn(4, 4)

# Ez nem fogja x1-nek az összeg értékét adni
# Valóságban a 'None' értéket kapjuk majd
x1 = sumPrint(4, 4)

# Ez igen
x2 = sumReturn(4, 4)

9.3 Függvények dokumentálása

Pythonban a függvényeknek tipikusan az első parancssora egy komment. Ez a komment három dupla-idézőjel által van közrefogva, és úgy hívják, hogy docstring. Egy függvény így néz ki:

def volumeCylinder(radius, height):
    """Visszaad egy hengertérfogatot, a megadott sugár és magasság alapján."""
    pi = 3.141592653589
    volume = pi * radius ** 2 * height
    return volume

A jó dolog a docstring használatában az, hogy a komment kiemelhető, és a webre is kirakható, olyan eszközzel, amit úgy hívnak, hogy Sphinx. A legtöbb nyelv rendelkezik hasonló eszközzel, ami segít dokumentálni. Ez elég sok időt megtakarít, amikor nagyobb programokkal dolgozol.

9.4 Változó hatóköre

Videó: Változó hatóköre

A függvény használata bevezet egy olyan fogalmat, mint a hatókör. A hatókör az, ahol a kód változója él, ahol hozzáférhető. Példának, lásd alább:

# definiál egy egyszerű függvényt, ami
# x-t 22-vel tesz egyenlővé
def f():
    x = 22

#A függvény meghívása
f()
# Ez hibás, az x csak az f()-n belül létezik
print (x)

Az utolsó sor egy hibát fog generálni, mivel x csak az f() függvényen belül létezik. A változó, amit alkottunk, amikor az f() függvényt meghívjuk, és a memória, ahol tároltuk, törli, amint az f() végrehajtódott.

Sokkal zavaróbb szabály az, amely megengedi, hogy az f() függvény, a rajta kívül létrehozott változóhoz is hozzáférjen. A következő kódnál, x-t még azelőtt hozzuk létre, hogy f() függvényt létrehoznánk, és így fogjuk beolvasni az f() függvénybe.

# Készítsünk egy x változót, ami x-t 44-gyel teszi egyenlővé
x = 44

# Definiáljunk egy egyszerá függvényt, ami kiírja x-t
def f():
    print(x)

# Függvény meghívása
f()

A változók amiket egy függvény előtt hoztunk létre, olvashatóak a függvényben, de csak akkor, ha nem változtatjuk meg értékét a függvényen belül. Ez a kód, nagyon hasonló a fentihez, vagyis hibás. A számítógép nem fogja érteni, hogy az x mire vonatkozik.

# Készítünk egy x válozót, és feltöltkük a 44 értékkel
x=44

# Definiálunk egy egyszerű függvényt, ami kiírja x-t
def f():
    x += 1
    print(x)

# Függvény lehívása
f()

Más nyelveknek sokkal összetettebb szabályai vannak a változók létrehozásával kapcsolatban és hatókörével, mint a pythonnak van. Mivel a Python előrelátó, ezért jó bevezető nyelv.

9.5 Másolás általi átadás

A függvények átadják az értéküket azzal, hogy lemásolják azt. Például:

# Definiáluink egy egyszerű függvényt, ami kiírja x-t
def f(x):
    x += 1
    print(x)

#  y megadása
y = 10
# Függvény meghívása
f(y)
# Az y kiírása, hogy lássuk változott-e
print(y)

Az y értéke nem változik, még akkor sem, ha az f() függvény megnöveli az átadott értéket. Mindkét változó egy paraméter, és a függvényben egy új paraméter. A változó értéke lemásolódott onnan, ahonnan meghívták azt.

Ez érthető, ha tovább vizsgálunk egy példát. Ahol kicsit zavaró lehet az, hogy a kód is és a függvény is ugyanolyan nevű változót használ. A lenti kód csak jelképes a listát tekintve, de szerencsésebb y helyett az x-t használni.

# Definiál egy egyszerű függvényt, ami kiírja x-t
def f(x):
    x += 1
    print(x)

#  x megadása
x = 10
# Függvény megadása
f(x)
# Írassuk ki x-t, hogy lássuk megváltozott-e
print(x)

A kimenet ugyanaz, mintha a program y -t használna változónévként. Noha, mindkét program x-t használja változónévként, nekünk két különböző változónk van. Van egy x változónk a függvényen belül, és egy a függvényen kívül.

9.6 Függvények, amik függvényeket hívnak

Az is lehetséges, hogy egy függvény meghívjon egy másik függvényt. Például, mondjuk egy ilyen függvényed van:

def armOut(whichArm, palmUpOrDown):
	#a kód itt fog futni

def handGrab(hand, arm):
	# a kód itt fog futni

Azután egy másik függvényt hozz létre, ami meghívja az előzőt:

def macarena():
	armOut("right", "down")
	armOut("left", "down")
	armOut("right", "up")
	armOut("left", "up")
	handGrab("right", "left arm")
	handGrab("left", "right arm")
	# etc

9.7 Főbb függvények és globálok

Amint a program nagyobb lesz, fontossá válik, hogy a kód szervezettt maradjon, és még így is működjön. A Python lehetővé teszi, hogy olyan kódot írjunk, ami a nullás bekezdés szintjén van. Ez jellemzi a legtöbb programot, amit eddig írtunk. A kódjaink balra igazodtak, és nem kerültek függvényekbe.

Ez az elgondolás olyan, mint a ruhák halomba rakása a padló közepén, vagy mikor minden szerszámot egy csomóban tartasz egy munkaasztalon. Ez csak akkor működik, amikor nincs sok tennivalód. De, még akkor is rendetlennek hat.

Minden kódod és minden változód betehető egy függvénybe. Ez fogja rendszerezetten tartani a kódodat. Segíteni fog akkor is, amikor egy bugot keresel a programban. Változóid, amiket a nullás bekezdési szinten hozol létre, a globális változók. Globális változók elég rossz dolgok. Miért? Mivel a kód bármely részén meg lehet változtatni az értékét. Ha van egy 50.000 soros programod, minden sorod megváltoztathatja a változód. Ha viszont egy függvényben tartod, akkor csak ez a függvénykód képes megváltoztatni a változódat. Így, ha van egy nem várt értéked a változóban, akkor is csak 50 sor kódot kell átnézned a függvényben. Máskülönben, át kellene néznes az egész program összes sorát.

Jobb módszer programírásra Pythonban a következő minta:

def main():
	print("Hello world.")

main()

Ez esetben az összes kód, amit én a nullás bekezdési szinten futtatok be lett téve egy main függvénybe. Az utolsó sora a fájlnak hívja meg a main-t.

Na várjunk csak! Van itt még egy probléma, amit korrigálnunk kell. A 15-dik fejezetben, beszélni fogunk arról, hogyan tördeljük a programunkat több fájlba. Használhatjuk az import parancsot, hogy betöltsük a függvényt más általunk kreált modulból. Ha az import parancsot meghívjuk, akkor ez automatikusan lefuttatja a main függvényt. Nem akarjuk ezt. Olyan programot akarunk, amit tudunk irányítani.

A probléma kijavítására meg kellene tesztelnünk a programunkat egy globális változóra, amit a Python automatikusan definiál. (Tudom, most mondtam, hogy a globál rossz, jó?) Ezt a változót úgy hívják: __name__, két aláhúzással előtte és utána is. Ezzel ellenőrízhetjük, hogy egy kód importálva lett vagy futtatva. Ha a kódunk fut, akkor a Python automatikusan átállítja ezt a változó értéket __main__-re. Egy egyszerű if paranccsal csak meghívjuk a main függvényt, ha kód fut. Máskülönben a kód csak definiálja a main függvényt. A kódot, ami importálva lett, ez meg tudja hívni, amikor szükségünk van rá.

Így néz ki az, ahogyan minden Python kódnak futnia kéne:

def main():
	print("Hello world.")

if __name__ == "__main__":
    main()

Az egyik ok, amiért szeretem a Pythont az az, hogy első nyelvként neked nem kell ilyesmivel foglalkoznod mindaddig, amíg nem szükséges. Más nyelvek, mint a Java, már használják már akkor is, amikor kicsiny a programod.

Azért, hogy könnyebbé tegyük a dolgokat, nem fogunk bemutatni példát ezekre a mintákra. De ez után a könyv után a programjaid elég összetettek lesznek ahhoz, hogy az életed könnyebbé váljon akkor, ha "nem dobod az összes ruhát egy kupacba a földön".

Ha te egy szuper-lelkes egyén vagy a programozást illetően, akkor próbáld a programjaidat már ezen elvek szerint írni mostantól. Noha kezdetben sokkal nehezebb lesz, később meghálálja magát. Továbbá jó, ha megtanulod, hogyan menedzseld az adataidat és hatókörüket.

Itt egy példa arra, hogy milyen PyGame sablont használj ezen minták szerint:
pygame_base_template_proper.py

Nem muszáj ezt a sablont használni, ha én tartom neked ezt a kurzust. Nekem nem jelent gondot, hogy a ruháidat a földre hajigálod az első szemeszterben. Már annak is örülök, hogy ruhában vagy. (A tisztaságmániákusok részére jegyzem meg, hogy ezt a programot majd tovább tisztítjuk az osztályok fejezetben.)

9.8 Review

9.8.1 Multiple Choice Quiz

Click here for a multiple-choice quiz.

9.8.2 Short Answer Worksheet

Click here for the chapter worksheet.

9.8.3 Lab

Click here for the chapter lab.


You are not logged in. Log in here and track your progress.