Ügyességi játékok programozása
Pythonnal és Pygame-melChapter 18: Kivételek
Ha valami rosszul működik a programmal, akkor szeretnéd-e azt, hogy a felhasználó egy nagy piros Python hibaüzenetet lásson? Szeretnéd, hogy a programod futása felfüggesztődjön? Ha nem, akkor szükséged lesz a kivételekre.
A kivételeket akkor használjuk, amikor az abnormális lehetőségeket kell kezelnünk, melyek a kód végrehajtása során jelentkeznek. A kivételek gyakran fájl- és hálózat műveletek. Ez lehetővé teszi a kódnak, hogy ügyesen kezelje, ha például kifut a tárhelyből, vagy hálózati probléma lép fel, vagy feltételek nem egyeznek.
18.1 Szójegyzék
Sokféle terminus és kifejezés van használatban a kivételekkel kapcsolatban. Íme a leggyakoribbak:
- Kivétel: Ez a kifejezés kétféle dolgot is jelenthet. Először, jelentheti a feltételt, ami okozta az abnormális program viselkedést. Vagy utalhat egy objektumra, ami az adat állapotát mutatja. Mindkét kivétel esetén rendelkezünk egy objektummal, ami információt tárol róla.
- Kivételkezelés: A kivételkezelési eljárás nem más, mit egy normális program folyamat.
- elkapott blokk vagy kivételek blokkja: Olyan kód, ami kezeli az abnormális helyzetet, úgymond elkapta a kivételt.
- Throw vagy raise: Amikor egy nem akart feltételt felfedezünk a programunkban, akkor egy kivétel objektum példány jön létre. Utána ez lesz odadobva (throw), vagy ez lesz felemelve, felkeltve (raise) a kódban, ami elkapta.
- Kezeletlen kivétel vagy Meglógott kivétel: Olyan kivétel, ami oda lett dobva, de sosem lett elkapva. Ez általában egy hiba eredménye és a program ilyenkor össze is omlik.
- Próba blokk: Olyan kódok, melyeknek tartalmazniuk kéne egy odadobott kivételt.
A legtöbb programnyelv a “throw” és a “catch” szavakat használja. A Python viszont nem, helyette a “raise” és “exception”-t. Mi itt a throw/catch szavakat fogjuk használni, mivel ez a leggyakoribb és legelfogadottabb az iparágban.
18.2 Kivételkezelés
A kivételkezelés kódja elég egyszerű. Lássuk az alábbi példát:
# nullával osztás try: x = 5 / 0 except: print("Hiba: nullával osztás")
A második sorban van egy try parancs. Minden alatta lévő, tabulátoros sor egy Próba blokk. Nem kellene, hogy legyen be nem húzott sor a try blokk alatt, hacsak nem except paranccsal kezdődik. A Próba blokk definiál egy csapat kódot, ami végre fog hajtódni.
Ha van egy kivétel, ami a kód futása során megjelenik, akkor a végrehajtás azonnal odaugrik a "catch" blokkhoz. Ez a kódblokk is tabulátoros behúzással van jelölve, hogy az except parancs alá tartozik a negyedik sorban. Ez a kód a felelős a hibakezelésért.
Egy program használhat kivételeket arra, hogy elkapjon hibákat, amik a szövegből számmá való alakítás során jönnek létre például:
# Hibás szám átalakítás try: x = int("fred") except: print ("Hiba, amikor fred-t számmá alakítjuk.")
Ez a kivétel azért lesz bedobva a hármas soron, mivel a fred nevű értéket nem lehet egész számmá alakítani. Az ötödik sor egy hibaüzenetet ad vissza eredményül.
Alább látható egy kiterjesztett verziója ennek a példának. Ez hibát próbál le, és a felhasználó inputját vizsgálja, hogy egész számot ad-e meg. Ha a felhasználó nem egész számot ad meg, akkor a számítógép kéri, hogy azt próbálja. A kód kivétel kezelést hajt végre, hogy egy lehetséges konverziós hibát elkerüljön, ami az ötös sorban látható. Ha a felhasználó mást ad meg, és nem egészet, akkor egy kivétel lesz odadobva, amikor a szám megjelenik az ötös sorban. A hatos sor lódja a numberEntered értéke nem áll át True-ra, ha egy kivételkezelés történik az előző sorban.
numberEntered = False while not numberEntered: numberString = input("Adj meg egy egészet: ") try: n = int(numberString) numberEntered = True except: print ("Hiba, érvénytelen egész szám.")
A fájlok részlegesen akadoznak, amikor hiba jelenik meg a futásuk során. Egy tárhely megtelhet, a felhasználó törölhet egy fájlt, vagy elmozgathatja, vagy USB meghajtót kiveszik menet közben. Ezek a típusú hibák is könnyen elkaphatók kivétel kezeléssel.
# fájl megnyitás: hiba try: my_file = open("myfile.txt") except: print("Error opening file")
Sokféle típusú hibát lehet elkapni és kezelni különbözőképp. Hasznos lehet egy kicsit finomabb hibaüzenetet használni, ahelyett, hogy "hiba jelentkezett".
Az alábbi kódban különböző típusú hibák jelennek meg az 5-8 sorok közt. A kivétel/except parancs után az IOError, a kilencedik sorban csak azt kezeli, hogy a beolvasás és megjelenítés (IO) ne hibázzon. Hasonlóan a 11-dik sorban csak a konvertált értékek hibáit kezeljük, míg a 13-dik sor a nullával osztást figyeli. Az utolsó kivétel kezelés a 15-dik sorban, ez már minden más hibára ad üzenetet, amit fent nem vettünk figyelembe. Ez az utolsó except, ami mindent megfog.
Az első sor beolvassa a sys könyvtárat, amit a 16-dik sorban fogunk használni, szintén hibakezeléskor.
import sys # többféle hiba try: my_file = open("myfile.txt") my_line = my_file.readline() my_int = int(s.strip()) my_calculated_value = 101 / my_int except IOError: print("I/O error") except ValueError: print("Could not convert data to an integer.") except ZeroDivisionError: print("Division by zero error") except: print("Unexpected error:", sys.exc_info()[0])
A beépített kivételek elérhetők erről a webhelyről:
http://docs.python.org/library/exceptions.html
18.3 Példa: Pontszámok mentése
Ez azt mutatja meg, hogyan mentsük el a pontszámokat a játékok közt, A pontszám tárolva van egy fájlban: high_score.txt.
""" Show how to use exceptions to save a high score for a game. Sample Python/Pygame Programs Simpson College Computer Science http://programarcadegames.com/ http://simpson.edu/computer-science/ """ def get_high_score(): # Default high score high_score = 0 # Try to read the high score from a file try: high_score_file = open("high_score.txt", "r") high_score = int(high_score_file.read()) high_score_file.close() print("The high score is", high_score) except IOError: # Error reading file, no high score print("There is no high score yet.") except ValueError: # There's a file there, but we don't understand the number. print("I'm confused. Starting with no high score.") return high_score def save_high_score(new_high_score): try: # Write the file to disk high_score_file = open("high_score.txt", "w") high_score_file.write(str(new_high_score)) high_score_file.close() except IOError: # Hm, can't write it. print("Unable to save the high score.") def main(): """ Main program is here. """ # Get the high score high_score = get_high_score() # Get the score from the current game current_score = 0 try: # Ask the user for his/her score current_score = int(input("What is your score? ")) except ValueError: # Error, can't turn what they typed into a number print("I don't understand what you typed.") # See if we have a new high score if current_score > high_score: # We do! Save to disk print("Yea! New high score!") save_high_score(current_score) else: print("Better luck next time.") # Call the main function, start up the game if __name__ == "__main__": main()
18.4 Kivétel objektumok
További információkat kaphatunk egy hibáról, ha behúzzuk azokat egy kivétel objektumból. Ez az objektum letöltésre kerülhet miközben elkaptuk a hibát, mindössze az as kulcsszót kell használnunk. Például:
try: x = 5 / 0 except ZeroDivisionError as e: print(e)
Az e változó további információkra mutat a kivétellel kapcsolatban, amiket majd kiírat. Sokkal többet is lehetne szólni a kivételek objektumairól, de az túlmutat a fejezet célján.
18.5 Kivétel léltrehozása
Kivételeket létrehozhatunk a raise paranccsak. Például:
# kivétel létrehozása def getInput(): userInput = input("Üss be valamit: ") if len(userInput) == 0: raise IOError("a felhasználó semmit se gépelt be") getInput()
Próbáld ki a fenti kódot, és adj hozzá még kivétel kezelést, mondjuk az IOError-t.
Lehetőség van arra, hogy beállítás szerint hozzunk létre kivételeket, de
ez is a könyv célján mutatna túl. A komolyabb olvasók további információt
találhatnak itt:
http://docs.python.org/tutorial/errors.html#raising-
18.6 Helyes kivétel kezelése használata
A kivételeket nem kéne használni olyankor, amikor az if feltételek képesek kezelni ezeket a folyamatokat. A normál kódnak nem kéne találnia kivételeket, amikor a "boldog" kód fut hibátlanul. Jól felépített Próbakódokat könnyű követni, de az olyanokat, melyek számtalan kivételt vonnak be majd átadják azt egy másik programozónak egy rémálom lehet. (Egyszer megkértek arra, hogy debuggoljak egy kódot, ami XML doksit olvas be. Tucatnyi kivételt generált minden sorhoz, amit a fájl beolvasott. Nagyon lassú volt, rengeteg hibalehetőséggel. Az a kód szinte sosem generált volna egyetlen kivételt sem, amennyiben normálisan olvastuk be a fájlt.)
18.7 Áttekintés
18.7.1 Kvízkérdések
Click here for a multiple-choice quiz.
18.7.2 Feladatlap
Click here for the chapter worksheet.
You are not logged in. Log in here and track your progress.
English version by Paul Vincent Craven
Spanish version by Antonio Rodríguez Verdugo
Russian version by Vladimir Slav
Turkish version by Güray Yildirim
Portuguese version by Armando Marques Sobrinho and Tati Carvalho
Dutch version by Frank Waegeman
Hungarian version by Nagy Attila
Finnish version by Jouko Järvenpää
French version by Franco Rossi
Korean version by Kim Zeung-Il
Chinese version by Kai Lin