Imprimer la pile d'appels actuelle à partir d'une méthode en code Python

276

En Python, comment puis-je imprimer la pile d'appels actuelle à partir d'une méthode (à des fins de débogage).

soi-même
la source

Réponses:

319

Voici un exemple pour obtenir la pile via le module traceback et l'imprimer:

import traceback

def f():
    g()

def g():
    for line in traceback.format_stack():
        print(line.strip())

f()

# Prints:
# File "so-stack.py", line 10, in <module>
#     f()
# File "so-stack.py", line 4, in f
#     g()
# File "so-stack.py", line 7, in g
#     for line in traceback.format_stack():

Si vous ne voulez vraiment imprimer que la pile sur stderr, vous pouvez utiliser:

traceback.print_stack()

Ou pour imprimer sur stdout (utile si vous souhaitez conserver la sortie redirigée ensemble), utilisez:

traceback.print_stack(file=sys.stdout)

Mais l'obtenir via traceback.format_stack()vous permet de faire ce que vous voulez avec.

RichieHindle
la source
Comment faire de même pour tous les autres threads (je parle de threads que je ne contrôle pas)  ?
user2284570
Peut-être que je manque quelque chose ici, mais vous appelez f dont le seul but est d'appeler g et ne fait rien d'autre. Pourquoi
Chris
6
@Chris: Ce n'est qu'un exemple. Il a plusieurs fonctions pour indiquer clairement que format_stack () imprime tous les appels sur la pile.
RichieHindle
Si vous souhaitez obtenir une sortie plus détaillée (y compris les vars, etc.), consultez cette question connexe et celle-ci .
Albert
@ user2284570: Vous pouvez utiliser sys._current_frames(). Par exemple, py_better_exchookdump_all_thread_tracebacks fait cela (avertissement: j'ai écrit cela).
Albert
93
import traceback
traceback.print_stack()
Mark Roddy
la source
8
En fait, j'aime traceback.print_exc()ce qui vous donne presque la même chose que vous auriez obtenue sans l' excepténoncé (et est également moins codant que la réponse acceptée).
martineau
34
traceback.print_exc()imprime la trace de la pile pour toute exception que vous pourriez gérer - mais cela ne résout pas la question d'origine, qui est de savoir comment imprimer la pile actuelle ("où vous êtes maintenant" par opposition à "où était votre code lors de la dernière exception) off, if any ".)
Tom Swirly
17

Si vous utilisez le débogueur python, non seulement le sondage interactif des variables, mais vous pouvez obtenir la pile d'appels avec la commande "where" ou "w".

Donc en haut de votre programme

import pdb

Ensuite, dans le code où vous voulez voir ce qui se passe

pdb.set_trace()

et vous êtes tombé dans une invite

Keir
la source
2
Je programme en Python depuis plus d'une décennie. Il y a tellement de fois que j'aurais pu utiliser ça! Je ne peux pas croire que je suis en train de le découvrir.
hosford42
1
Comment cela se rapporte- wheret-il?
skia.heliou
4
Pour répondre à la partie "où" de la question: Après avoir reçu l'invite pdb, tapez (pdb) simplement whereet il imprimera la trace de la pile sur le terminal.
stephenmm
1
Python 3.7 et supérieur ont une fonction intégrée breakpoint()qui évite d'avoir à importer pdb.
user650654
6

pour ceux qui ont besoin d'imprimer la pile d'appels tout en utilisant pdb, faites simplement

(Pdb) where
souris RAT
la source
2

Voici une variation de l'excellente réponse de @ RichieHindle qui implémente un décorateur qui peut être appliqué sélectivement aux fonctions comme vous le souhaitez. Fonctionne avec Python 2.7.14 et 3.6.4.

from __future__ import print_function
import functools
import traceback
import sys

INDENT = 4*' '

def stacktrace(func):
    @functools.wraps(func)
    def wrapped(*args, **kwds):
        # Get all but last line returned by traceback.format_stack()
        # which is the line below.
        callstack = '\n'.join([INDENT+line.strip() for line in traceback.format_stack()][:-1])
        print('{}() called:'.format(func.__name__))
        print(callstack)
        return func(*args, **kwds)

    return wrapped

@stacktrace
def test_func():
    return 42

print(test_func())

Sortie de l'échantillon:

test_func() called:
    File "stacktrace_decorator.py", line 28, in <module>
    print(test_func())
42
martineau
la source
A écrit ma propre version décoratrice avant de voir ça. A voté.
Sida Zhou
0

Installez Inspect-it

pip3 install inspect-it --user

Code

import inspect;print(*['\n\x1b[0;36;1m| \x1b[0;32;1m{:25}\x1b[0;36;1m| \x1b[0;35;1m{}'.format(str(x.function), x.filename+'\x1b[0;31;1m:'+str(x.lineno)+'\x1b[0m') for x in inspect.stack()])

vous pouvez créer un extrait de cette ligne

il vous montrera une liste de la pile d'appels de fonction avec un nom de fichier et un numéro de ligne

liste du début à l'endroit où vous mettez cette ligne

MohitGhodasara
la source