247 lines
5.9 KiB
Plaintext
247 lines
5.9 KiB
Plaintext
|
.. default-role:: literal
|
|||
|
|
|||
|
Le style de programmation par exceptions
|
|||
|
========================================
|
|||
|
|
|||
|
.. glossary::
|
|||
|
|
|||
|
Exception
|
|||
|
|
|||
|
Les exceptions permettent de récupérer des situations où le calcul ne peut pas se poursuivre.
|
|||
|
Dans ces cas, un récupérateur d'exceptions permet de continuer le calcul
|
|||
|
sachant qu'une des branches a échoué.
|
|||
|
|
|||
|
|
|||
|
Exemple d':term:`exception`
|
|||
|
|
|||
|
>>> assert 2 == 1
|
|||
|
Traceback (most recent call last):
|
|||
|
File "<stdin>", line 1, in <module>
|
|||
|
AssertionError
|
|||
|
|
|||
|
|
|||
|
|
|||
|
La règle du samouraï
|
|||
|
----------------------
|
|||
|
|
|||
|
.. important:: règle du Samouraï : une fonction doit renvoyer le résultat escompté
|
|||
|
ou bien lever une exception
|
|||
|
|
|||
|
|
|||
|
>>> def function_raise(x):
|
|||
|
... if not type(x) == int:
|
|||
|
... raise TypeError("Pas le bon type")
|
|||
|
... else:
|
|||
|
... return x + 1
|
|||
|
...
|
|||
|
>>> try:
|
|||
|
... e = function_raise("une string")
|
|||
|
... except TypeError, e:
|
|||
|
... print e
|
|||
|
...
|
|||
|
Pas le bon type
|
|||
|
>>
|
|||
|
|
|||
|
- la fonction doit renvoyer des valeurs du même type (ou bien ``None``)
|
|||
|
- la fonction doit lever une exception appropriée
|
|||
|
|
|||
|
|
|||
|
utiliser la pile d'appel pour débugger
|
|||
|
---------------------------------------
|
|||
|
|
|||
|
Utiliser la pile d'appels, elle se lit de bas en haut. Il est possible de
|
|||
|
provoquer cette pile d'appels.
|
|||
|
|
|||
|
::
|
|||
|
|
|||
|
import traceback
|
|||
|
traceback.print_exc()
|
|||
|
|
|||
|
.. todo:: s'exercer à lire une pile d'appels un peu complexe.
|
|||
|
|
|||
|
|
|||
|
Traiter une exception avec
|
|||
|
|
|||
|
::
|
|||
|
|
|||
|
try:
|
|||
|
...
|
|||
|
except:
|
|||
|
import traceback
|
|||
|
traceback.print_exc()
|
|||
|
|
|||
|
else:
|
|||
|
bla bla
|
|||
|
finally:
|
|||
|
bla bla
|
|||
|
|
|||
|
.. attention:: ne **jamais** briser la pile d'appels sans savoir précisément
|
|||
|
ce que l'on fait, et remonter une autre exception
|
|||
|
|
|||
|
Exemple :
|
|||
|
|
|||
|
|
|||
|
>>> def function(x):
|
|||
|
... if x == 1: raise TypeError("pas le bon type")
|
|||
|
... else: return "ok"
|
|||
|
...
|
|||
|
>>> def function2(x):
|
|||
|
... try:
|
|||
|
... return "c'est " + function(x)
|
|||
|
... except TypeError, e:
|
|||
|
... raise AssertionError("on a une autre exception là")
|
|||
|
...
|
|||
|
>>> try:
|
|||
|
... function2(1)
|
|||
|
... except Exception, e:
|
|||
|
... print e
|
|||
|
...
|
|||
|
on a une autre exception là
|
|||
|
>>>
|
|||
|
|
|||
|
Le raise (ou le re-raise) est souvent utilisé pour lever une exception métier
|
|||
|
et cacher une exception système de bas niveau.
|
|||
|
|
|||
|
exemple::
|
|||
|
|
|||
|
try:
|
|||
|
add_s(dn, listdata)
|
|||
|
except ldap.LDAPError, err:
|
|||
|
raise MyOwnError(msg + str(err))
|
|||
|
except Exception:
|
|||
|
pass
|
|||
|
|
|||
|
.. todo:: dans quel cas entrons-nous dans le `else` ? dans le `finally` ?
|
|||
|
|
|||
|
.. todo:: créer des exceptions métier
|
|||
|
|
|||
|
exemple d'exceptions *dans la vraie vie*::
|
|||
|
|
|||
|
"user defined exceptions"
|
|||
|
|
|||
|
|
|||
|
# Exceptions for an Option
|
|||
|
class PropertiesOptionError(AttributeError):
|
|||
|
"attempt to access to an option with a property that is not allowed"
|
|||
|
def __init__(self, msg, proptype):
|
|||
|
self.proptype = proptype
|
|||
|
super(PropertiesOptionError, self).__init__(msg)
|
|||
|
|
|||
|
|
|||
|
#____________________________________________________________
|
|||
|
# Exceptions for a Config
|
|||
|
class ConfigError(Exception):
|
|||
|
"""attempt to change an option's owner without a value
|
|||
|
or in case of `_cfgimpl_descr` is None
|
|||
|
or if a calculation cannot be carried out"""
|
|||
|
pass
|
|||
|
|
|||
|
|
|||
|
class ContextError(Exception):
|
|||
|
"""context needed but not given
|
|||
|
"""
|
|||
|
pass
|
|||
|
|
|||
|
|
|||
|
class ConflictError(Exception):
|
|||
|
"duplicate options are present in a single config"
|
|||
|
pass
|
|||
|
|
|||
|
|
|||
|
#____________________________________________________________
|
|||
|
# miscellaneous exceptions
|
|||
|
class RequirementError(Exception):
|
|||
|
"""a recursive loop occurs in the requirements tree
|
|||
|
requires
|
|||
|
"""
|
|||
|
pass
|
|||
|
|
|||
|
|
|||
|
class SlaveError(Exception):
|
|||
|
"problem with a slave's value length"
|
|||
|
pass
|
|||
|
|
|||
|
|
|||
|
class ConstError(TypeError):
|
|||
|
"no uniq value in _NameSpace"
|
|||
|
pass
|
|||
|
|
|||
|
Créer le plus possible ses propres exceptions spécifiques au programme
|
|||
|
La programmation par exception peut vite devenir un style de programmation
|
|||
|
très utilisé. C'est assez agréable mais le réserver pour la gestion d'une situation
|
|||
|
particulière, que ça reste une intervention pour les cas non gérés par le programme
|
|||
|
(en général).
|
|||
|
|
|||
|
Les exceptions imbriquées
|
|||
|
--------------------------------
|
|||
|
|
|||
|
>>> try:
|
|||
|
... ma_func()
|
|||
|
... except TypeError, e:
|
|||
|
... do_something()
|
|||
|
... except Exception, e:
|
|||
|
... do_somethin_else()
|
|||
|
...
|
|||
|
|
|||
|
Exemple de programme utilisant massivement la programmation par exceptions :
|
|||
|
`tiramisu`_
|
|||
|
|
|||
|
.. _tiramisu: http://tiramisu.labs.libre-entreprise.org/
|
|||
|
|
|||
|
|
|||
|
La hiérarchie des exceptions
|
|||
|
-----------------------------
|
|||
|
|
|||
|
Extrait de la documentation officielle::
|
|||
|
|
|||
|
BaseException
|
|||
|
+-- SystemExit
|
|||
|
+-- KeyboardInterrupt
|
|||
|
+-- GeneratorExit
|
|||
|
+-- Exception
|
|||
|
+-- StopIteration
|
|||
|
+-- StandardError
|
|||
|
| +-- BufferError
|
|||
|
| +-- ArithmeticError
|
|||
|
| | +-- FloatingPointError
|
|||
|
| | +-- OverflowError
|
|||
|
| | +-- ZeroDivisionError
|
|||
|
| +-- AssertionError
|
|||
|
| +-- AttributeError
|
|||
|
| +-- EnvironmentError
|
|||
|
| | +-- IOError
|
|||
|
| | +-- OSError
|
|||
|
| | +-- WindowsError (Windows)
|
|||
|
| | +-- VMSError (VMS)
|
|||
|
| +-- EOFError
|
|||
|
| +-- ImportError
|
|||
|
| +-- LookupError
|
|||
|
| | +-- IndexError
|
|||
|
| | +-- KeyError
|
|||
|
| +-- MemoryError
|
|||
|
| +-- NameError
|
|||
|
| | +-- UnboundLocalError
|
|||
|
| +-- ReferenceError
|
|||
|
| +-- RuntimeError
|
|||
|
| | +-- NotImplementedError
|
|||
|
| +-- SyntaxError
|
|||
|
| | +-- IndentationError
|
|||
|
| | +-- TabError
|
|||
|
| +-- SystemError
|
|||
|
| +-- TypeError
|
|||
|
| +-- ValueError
|
|||
|
| +-- UnicodeError
|
|||
|
| +-- UnicodeDecodeError
|
|||
|
| +-- UnicodeEncodeError
|
|||
|
| +-- UnicodeTranslateError
|
|||
|
+-- Warning
|
|||
|
+-- DeprecationWarning
|
|||
|
+-- PendingDeprecationWarning
|
|||
|
+-- RuntimeWarning
|
|||
|
+-- SyntaxWarning
|
|||
|
+-- UserWarning
|
|||
|
+-- FutureWarning
|
|||
|
+-- ImportWarning
|
|||
|
+-- UnicodeWarning
|
|||
|
+-- BytesWarning
|