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

Chapter 18: Kivételek

Videó:Kivétel kezelés

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:


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.