Instruilo por la programlingvo Pitono

Bonvolu sendi korektojn, proponojn, kaj sugestojn al vilcxjo ĉe esperanto-me.org

Eraroj kaj Esceptoj

Sintaksaj Eraroj
Esceptoj
Trakti Esceptojn
Levigi Esceptojn
Uzanto-definitaj Esceptoj
Defino de Purigaj Agadoj

Ĝis nun, erara mesaĝoj estas nur menciitaj.

Estas almenaŭ du malsamaj tipoj de eraroj: sintaksaj eraroj kaj esceptoj.

Sintaksaj Eraroj

Sintaksaj eraroj estas la plej oftaj eraroj ricevitaj kiam vi ankoraŭ lernas Pitonon:

   >>> while true print 'Saluton, mondo'
File "<stdin>", line 1
while true print 'Saluton, mondo'
    ^
SyntaxError: invalid syntax

La sintaksilo ripetas la linion kiu havas la eraron kaj videbligas etan ‘sagon’, kiu indikas la plej fruan punkton en la linio kie eraro estis trovita. La eraro estas trovita je la aĵo antaŭ la sago: en la ekzemplo, la eraro estas trovita je la prafunkcio print, ĉar dupunkto (:) mankas antaŭ ĝin. Dosiera nomo kaj linia numero estas videbligitaj por ke vi povas trovi linion se ĝi estas en skripto.

Esceptoj

Eĉ kiam instrukcio estas sintakse ĝusta, eraro eble okazas dum ĝia plenumado. Eraroj dum plenumado oni nomas esceptojn kaj ne devas esti fatalaj; vi baldaŭ lernos procedojn por trakti ilin en Pitonaj programoj. Se programo ne havas kodon por kapti kaj trakti esceptojn, rezulto estas erara mesaĝo.

Jen ekzemplo:

   >>> 10 * (1/0)
Traceback (innermost last):
File "<stdin>", line 1
ZeroDivisionError: integer division or modulo

>>> 4 + spamo*3
Traceback (innermost last):
File "<stdin>", line 1
NameError: name 'spamo' is not defined
>>> '2' + 2
Traceback (innermost last):
File "<stdin>", line 1
TypeError: illegal argument type for built-in operation

La lasta linio de la erara mesaĝo diras tion kio okazis. Estas diversaj tipoj da esceptoj, kaj la tipo estas videbligita kiel parto de la mesaĝo. La tipoj en la ekzemploj estas nuldivida eraro ZeroDivisionError, noma eraro NameError kaj tipa eraro TypeError. Pitono enmetas la nomon de la escepto en la eraran linion por ĉiuj primativaj esceptoj, se ne nepre por esceptoj definita de la programisto. (tamen estas utila konvencio).

La cetero de la erara linio enhavas detalojn, kies signifon dependas de la escepta tipo.

La antaŭa parto de la mesaĝo videbligas la situacion en kiu la escepto okazis, en la formo de staka retrospuro. Generale, ĝi enhavas stakan retrospuron kiu listas kodoliniojn; tamen ne videbligas liniojn kiu estis legita el norma enigilo.

La Library Reference listas la primativajn esceptojn kaj iliajn signifojn.

Trakti Esceptojn

Vi povas skribi programojn kiuj traktas elektitajn esceptojn. Rigardu la jena ekzemplo, kiu videbligas tabelon de inversoj de iu glitpunktaj numeroj:

   >>> numeroj = [0.3333, 2.5, 0, 10]
>>> for a in numeroj:
...     print a,
...     try:
...        print 1.0 / a
...     except ZeroDivisionError:
...        print '*** ne havas inverson ***'
...    
0.3333 3.00030003
2.5 0.4
0 *** ne havas inverson ***
10 0.1

La instrukcio try funkcias jene:

Unue, la kodogrupo try (la instrukcioj inter la ŝlosilvortoj try kaj except) estas lancita. Se escepto ne okazas, la kodogrupo except estas ignorita kaj la kodogrupo try finiĝos.

Se escepto okazas en la kodogrupo try, la cetero de la kodogrupo try estas ignorita. Se la tipo de escepto respondas al la escepto nomita post la primitiva vorto except, la kodogrupo except estas lancita, tiam la instrukcioj post la tuta grupo try-except estas lancitaj.

Oni povas nesti grupojn try-except. Se escepto okazas, kaj ne respondas al la escepto nomita en la kodogrupo except, la escepto estas sendita laŭvice al ĉiu plialtnivela kodogrupo try; se ne estas responda kodogrupo except , eraro okazas kaj la programo ĉesas funkcii. Eraro mesaĝo estas videbligita.

La instrukcio try povas havi pli ol unu kodogrupo except , por trakti diversajn esceptojn. Maksimume, unu kodogrupo except estos lancita. La kodogrupo except nur traktas esceptojn kiu okazis en la kodogrupo try , ne tiuj kiuj okazas en alia(j) kodogrupo(j) except . Escepto povas nomi multajn esceptojn en enkrampa listo, ekz.:

   ... except (RuntimeError, TypeError, NameError):
...  <escepta kodo>

La lasta kodogrupo except povas ellasi nomo(j) de esceptoj, do nomo estas ĵokero (do respondas al iu ajn escepto) Uzu ĉi tiun ilon zorge, ĉar vi facile kaŝi veran programan eraron per tio! Oni povas presi eraran mesaĝon kaj poste relevi la escepton.

   import string, sys
try:
f = open('miadosiero.txt')
    s = f.readline()
    i = int(s.strip())
except IOError, (errno, strerror):
   print "en/el eraro(%s): %s" % (errno, strerror)
except ValueError:
   print "Ne povas konverti al entjero."
except:
   print "Neanticipita eraro:", sys.exc_info()[0]
    raise #relevi escepton (vidu 'Levi Escepton' sube)

La instrukcio try ... except havas nedevigan kodogrupon else, kiu devas sekvi la lastan kodogrupon except. La kodogrupo else estas lancita se la kodogrupo try ne levas escepton. Ekzemple:

   for arg in sys.argv:
   try:
  f = open(arg, 'r')
   except IOError:
   print 'ne povas malfermi', arg
   else:
   print arg, 'havas', len(f.readlines()),'liniojn'
     f.close()

Kiam escepto okazas, ĝi eble resendas valoron, nomita la argumento de la escepto. La ekzisto kaj tipo de la argumento dependas de la tipo de escepto.Por esceptoj kiu resendas argumentojn, variablo post la ekcepta nomo (aŭ listo) ricevos argumenton. Oportune, la eroj _getitem_ kaj _str_ enhavas la informon de la argumenton.:

   >>>try:
...    raise Exception('spamo', 'ovoj')
...except Exception, kazo:

...    print type(inst)# la escepta kazo
...    print inst.args # argumentoj metita en .args
...    print inst # per __str__, presu arg-ojn rekte
...    a, b = inst # per __getitem__, malpaku arg-ojn
...   print 'a =', a
...    print 'b =', b

...
<type 'instance'>
('spamo', 'ovoj')
('spamo', 'ovoj')
a = spamo
b = ovoj

La kodogrupo except ne nur traktas esceptojn kiuj okazas tuj en kodogrupo try , sed ankaŭ esceptojn kiuj okazas interne de funkcioj vokitaj (eĉ nerekte) de la kodogrupo try . Por ekzemplo:

   >>>def ne_sukcesas():
...    a = 1/0
...
>>>try:
...    ne_sukcesas()
...except ZeroDivisionError, detalo:
...    print 'Dumplenuma eraro:', detalo
...
Dumplenuma eraro: integer division or modulo

Levi Esceptojn

Oni uzas la instrukcion raise por okazigi specifan escepton. Por ekzemplo:

   >>> raise NameError, 'Hola'
Traceback (most recent call last):
  File "<stdin>", line 1 in ?
NameError: Hola

La unua argumento de la instrukcio raise nomas la escepton levotan. La nedeviga dua argumento estas la valoro resendota de la escepto.

Se vi volas nur rimarki la escepton, vi simple re-levos la escepton:

    >>> try:
...     raise NameError, 'Hola'
... except NameError:
...     print 'Escepto okazis - netraktita!'
...     raise
...

Escepto okazis - netraktita!
Traceback (most recent call last):
File "<stdin>", line 2, in ?
NameError: Hola

Uzanto-definitaj Esceptoj

Programisto povas nomi ilian propran escepton per kreado de nova escepto-klaso, Oni devus derivi esceptojn de klaso Exceptions aŭ rekte aŭ nerekte. Ekzemple:

   >>> class MiaEraro(Exception):
...     def __init__(self, valoro):
... self.valoro = valoro
... def __str__(self):
... return repr(self.valoro)
...
>>> try:
... raise MiaEraro(2*2)
... except MiaEraro, e:
... print 'Mia escepto okazis, valoro:', e.valoro
...
Mia escepto okazis, valoro: 4
>>> raise MiaEraro, 'oj!'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
__main__.MyError: 'oj!'

Esceptaj klasoj povas fari ĉion kion aliaj klasoj povas fari, sed kutime ili estas simplaj, provizante per atribuoj kiuj donas informon pri la eraro. Se diversaj eraoj eble okazus, ofte oni kreas bazan klason por eblaj exceptoj, kaj poste fari specifajn subklasojn por ĉiu tipo de eraro.

klaso Eraro(Exception):
"""Baza klaso por esceptoj en ĉi tiu modulo."""
pass
klaso EnigEraro(Eraro):
"""Escepto levigita por enigaj eraroj.
    Atribuoj:
esprimo -- eniga esprimo kie la eraro okazis
mesaĝo -- klarigo de la eraro
"""
    def __init__(mem, esprimo, mesaĝo):
mem.esprimo = esprimo
mem.mesaĝo = mesaĝo

Omi definas la plejparton de esceptoj per nomoj kiuj finas per la vorto 'eraro', simile al la praeseptoj.

Defino de Purigaj Agadoj

La instrukcio try havas alian nedevigan kodogrupon kiu definas purigajn agadojn ĉiam farotajn. Ekzemple:

   >>>try:
... raise KeyboardInterrupt
...finally:
...    print 'ĝis la, mondo!'
...
ĝis la, mondo!
Traceback (innermost last):
  File "<stdin>", line 2
KeyboardInterrupt

La kodogrupo finally estas lancita ĉu escepto okazis en kodogrupo try aŭ ne. Kiam escepto okazas, ĝi estas relevita post la kodogrupo finally finiĝos. La kodogrupo finally ankaŭ estas lancita je la punkto kiam programo saltas el la kodogrupo try pro instrukcio breakreturn.

La instrukcio try devas havi aŭ kodogrupo(j)n except aŭ instrukcion finally, sed ne ambaŭ.

Supren