web-dev-qa-db-fra.com

Comment enregistrer les valeurs traceback/sys.exc_info () dans une variable?

Je veux enregistrer le nom de l'erreur et les détails de la trace dans une variable. Voici ma tentative.

import sys
try:
    try:
        print x
    except Exception, ex:
        raise NameError
except Exception, er:
    print "0", sys.exc_info()[0]
    print "1", sys.exc_info()[1]
    print "2", sys.exc_info()[2]

Sortie:

0 <type 'exceptions.NameError'>
1 
2 <traceback object at 0xbd5fc8>

Sortie désirée:

0 NameError
1
2 Traceback (most recent call last):
  File "exception.py", line 6, in <module>
    raise NameError

P.S. Je sais que cela peut être fait facilement en utilisant le module traceback, mais je veux connaître l'utilisation de l'objet sys.exc_info () [2] ici.

90
codersofthedark

Voici comment je le fais:

>>> import traceback
>>> try:
...   int('k')
... except:
...   var = traceback.format_exc()
... 
>>> print var
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'k'

Cependant, vous devriez jeter un oeil à traceback documentation , car vous y trouverez peut-être des méthodes plus appropriées, selon la manière dont vous voulez traiter votre variable par la suite ...

126
mac

sys.exc_info () renvoie un Tuple avec trois valeurs (type, valeur, traceback). 

  1. Ici, type obtient le type d'exception de l'exception en cours de traitement
  2. valeur représente les arguments passés au constructeur de la classe d'exception  
  3. traceback contient les informations de pile, telles que l'emplacement où l'exception s'est produite, etc.

Par exemple, dans le programme suivant

try:

    a = 1/0

except Exception,e:

    exc_Tuple = sys.exc_info()

Maintenant, si nous imprimons le tuple, les valeurs seront les suivantes.

  1. la valeur exc_Tuple [0] sera " ZeroDivisionError "
  2. la valeur exc_Tuple [1] sera " division entière ou modulo par zéro " (Chaîne passée en paramètre à la classe d'exception)
  3. la valeur exc_Tuple [2] sera " objet de rétrolien à (adresse de mémoire quelconque) "

Les détails ci-dessus peuvent également être récupérés en imprimant simplement l'exception au format chaîne. 

print str(e)
18
keya

Utilisez traceback.extract_stack() si vous souhaitez un accès pratique aux noms de module et de fonction et aux numéros de ligne.

Utilisez ''.join(traceback.format_stack()) si vous voulez juste une chaîne qui ressemble à la sortie traceback.print_stack().

Notez que même avec ''.join(), vous obtiendrez une chaîne multiligne, car les éléments de format_stack() contiennent \n. Voir la sortie ci-dessous.

N'oubliez pas de import traceback.

Voici le résultat de traceback.extract_stack(). Ajout du formatage pour plus de lisibilité.

>>> traceback.extract_stack()
[
   ('<string>', 1, '<module>', None),
   ('C:\\Python\\lib\\idlelib\\run.py', 126, 'main', 'ret = method(*args, **kwargs)'),
   ('C:\\Python\\lib\\idlelib\\run.py', 353, 'runcode', 'exec(code, self.locals)'),
   ('<pyshell#1>', 1, '<module>', None)
]

Voici le résultat de ''.join(traceback.format_stack()). Ajout du formatage pour plus de lisibilité.

>>> ''.join(traceback.format_stack())
'  File "<string>", line 1, in <module>\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 126, in main\n
       ret = method(*args, **kwargs)\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 353, in runcode\n
       exec(code, self.locals)\n  File "<pyshell#2>", line 1, in <module>\n'
16
Nathan

Faites attention lorsque vous retirez l'objet exception ou l'objet traceback du gestionnaire d'exceptions, car cela entraînerait des références circulaires et que gc.collect() ne parviendrait pas à être collecté. Cela semble être un problème particulier dans l'environnement de bloc-notes ipython/jupyter où l'objet traceback n'est pas effacé au bon moment et même un appel explicite à gc.collect() dans la section finally ne fait rien. Et c’est un énorme problème si vous avez des objets énormes dont la mémoire ne récupère pas pour cette raison (par exemple, CUDA pour des exceptions de mémoire insuffisantes pour lesquelles cette solution n’a pas besoin d’un redémarrage complet du noyau pour pouvoir récupérer).

En général, si vous souhaitez enregistrer l'objet de suivi, vous devez le supprimer des références à locals(), comme suit:

import sys, traceback, gc
type, val, tb = None, None, None
try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
# some cleanup code
gc.collect()
# and then use the tb:
if tb:
    raise type(val).with_traceback(tb)

Dans le cas de jupyter notebook, vous devez au moins le faire dans le gestionnaire d'exceptions:

try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
    raise type(val).with_traceback(tb)
finally:
    # cleanup code in here
    gc.collect()

Testé avec Python 3.7.

p.s. Le problème avec ipython ou jupyter notebook env, c’est qu’il dispose de la magie %tb qui enregistre la trace et la rend disponible à tout moment ultérieurement. Et par conséquent, aucune locals() dans toutes les images participant à la trace ne sera libérée tant que le bloc-notes n'aura pas quitté ou qu'une autre exception ne remplacera la trace précédente stockée. C'est très problématique. Il ne faut pas stocker le traçage sans nettoyer ses cadres. Fix soumis ici .

1
stason

L'objet peut être utilisé comme paramètre dans la fonction Exception.with_traceback():

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))
0
Hansen D'Silva