2.25. Virheiden käsittely

Useimmat ajonaikaiset ongelmat Pythonissa ilmenevät poikkeuksina – nimettynä, jäsenneltynä tapana raportoida, että jokin meni pieleen. ValueError, TypeError, KeyError, OSError ja MemoryError ovat kaikki esimerkkejä; jokainen on luokka, ja sellaisen nostaminen pysäyttää nykyisen kutsun ja etsii käsittelijää ympäröivästä koodista.

2.25.1. try / except

Kääri koodilohko try -lauseeseen napataksesi minkä tahansa sen nostaman poikkeuksen:

try:
    n = int(input_text)
except ValueError:
    n = 0

Jos int(...) -muunnos epäonnistuu, suoritus siirtyy except -lohkoon sen sijaan, että virhe etenisi edelleen. Jos input_text oli kelvollinen kokonaislukumerkkijono, except -lohko ohitetaan.

Yhdellä try -lohkolla voi olla useita except -lohkoja, joista kukin nappaa erityyppisen virheen:

try:
    value = data[key]
except KeyError:
    value = None
except TypeError:
    value = -1

Python sovittaa järjestyksessä; ensimmäinen, jonka poikkeusluokka sopii, käsittelee ongelman. Exception -luokan (lähes kaiken perusluokka) nappaaminen käsittelee minkä tahansa virheen; varaa se ohjelman uloimmalle kerrokselle, jossa vaihtoehtona on kaatuminen.

Varoitus

Paljas except: (ei luokkaa avainsanan jälkeen) nappaa myös KeyboardInterrupt -poikkeuksen – poikkeuksen, jonka IDE lähettää, kun painat sen stop-painiketta keskeyttääksesi käynnissä olevan skriptin. Paljaaseen except: pass -lauseeseen käärityn silmukan nielee keskeytyksen ja jatkaa toimintaansa, jättäen skriptin pysäyttämiseen ainoaksi keinoksi virtakatkon.

Suosi except Exception: -muotoa paljaan except: -muodon sijaan, kun sinun on aidosti napattava laajasti. KeyboardInterrupt periytyy BaseException -luokasta, ei Exception -luokasta, joten except Exception: jättää stop-painikkeen toimintakuntoon.

2.25.1.1. Poikkeuksen tarkastelu

Lukeaksesi poikkeukseen liitetyn viestin, nimeä se as -avainsanalla:

try:
    f = open("data.txt")
except OSError as e:
    print("could not open file:", e)

as -lauseella sidottu muuttuja on voimassa vain except -lohkon sisällä.

2.25.2. else ja finally

try -lohkolla on kaksi valinnaista lisäystä.

else suoritetaan vain, kun try päättyi nostamatta poikkeusta:

try:
    value = compute()
except ValueError:
    print("bad input")
else:
    print("got", value)

”Mitä tehdä, kun se onnistui” -koodin sijoittaminen else -lohkoon pitää try -lohkon suppeana – vain rivi, joka saattaa epäonnistua, kuuluu try -lohkoon.

finally suoritetaan lopussa kaikissa tapauksissa – riippumatta siitä, onnistuiko try, nostiko se poikkeuksen joka käsiteltiin, vai nostiko se poikkeuksen joka on etenemässä:

try:
    do_work()
finally:
    cleanup()
Vuokaavio, joka näyttää neljä mahdollista polkua try / except / else / finally -rakenteen läpi: onnistuminen menee else-lohkoon ja sitten finally-lohkoon; napattu poikkeus menee except-lohkoon ja sitten finally-lohkoon; nappaamaton poikkeus menee finally-lohkoon ja sitten etenee eteenpäin.

finally suoritetaan aina. else suoritetaan vain poikkeuksettomalla polulla.

Useimmissa varaa/vapauta-kaavoissa suosi kontekstinhallintaa try / finally -parin sijaan – resurssi hallinnoi itse omaa siivoamistaan.

2.25.3. Yleisiä sisäänrakennettuja poikkeuksia

Lyhyt lista poikkeuksista, joihin törmäät usein:

  • ValueError – oikea tyyppi, väärä arvo (bytes([300]) – 300 on oikea tyyppi, mutta on kelvollisen tavualueen 0..255 ulkopuolella).

  • TypeError – kokonaan väärä tyyppi (len(42)).

  • KeyError – puuttuva avain dict -oliossa.

  • IndexError – indeksi sekvenssin lopun ohi.

  • AttributeError – olemattoman attribuutin käyttö ("abc".foo).

  • OSError – tiedostojärjestelmän tai I/O:n vika.

  • MemoryError – keko loppui. Muistirajoitteisessa ajoympäristössä tämä voi tapahtua normaalin toiminnan aikana – ei vain poikkeustapauksissa.