Imprimir pilha de chamadas atual de um método no código Python

276

No Python, como posso imprimir a pilha de chamadas atual de dentro de um método (para fins de depuração).

a si mesmo
fonte

Respostas:

319

Aqui está um exemplo de como obter a pilha através do módulo traceback e imprimi-la:

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():

Se você realmente deseja apenas imprimir a pilha no stderr, pode usar:

traceback.print_stack()

Ou para imprimir em stdout (útil se desejar manter a saída redirecionada em conjunto), use:

traceback.print_stack(file=sys.stdout)

Mas obtê-lo via traceback.format_stack()permite fazer o que quiser com ele.

RichieHindle
fonte
Como fazer o mesmo para todos os outros threads (estou falando de threads que não controlo)  ?
user2284570
Talvez eu esteja perdendo alguma coisa aqui, mas você chama f que é o único objetivo aqui é chamar g e não faz mais nada. Por que
Chris
6
@ Chris: É apenas um exemplo. Possui várias funções para deixar claro que format_stack () imprime todas as chamadas na pilha.
RichieHindle
Se você deseja obter uma saída mais detalhada (incluindo vars etc.), consulte esta questão relacionada e esta .
Albert
@ user2284570: Você pode usar sys._current_frames(). Por exemplo, py_better_exchookdump_all_thread_tracebacks faz isso (aviso: eu escrevi isso).
Albert
93
import traceback
traceback.print_stack()
Mark Roddy
fonte
8
Na verdade, eu gosto do traceback.print_exc()que lhe dá quase a mesma coisa que você obteria sem a exceptdeclaração (e também é menos codificadora do que a resposta aceita).
22680 martineau
34
traceback.print_exc()imprime o rastreamento de pilha para qualquer exceção que você possa estar manipulando - mas isso não resolve a questão original, que é como imprimir a pilha atual ("onde você está agora", em vez de "onde estava o seu código quando a última exceção ocorreu" off, se houver ".)
Tom Swirly
17

Se você usar o depurador python, não apenas investigará interativamente as variáveis, mas poderá obter a pilha de chamadas com o comando "where" ou "w".

Então, no topo do seu programa

import pdb

Em seguida, no código em que você deseja ver o que está acontecendo

pdb.set_trace()

e você cai em um prompt

Keir
fonte
2
Venho programando em Python há mais de uma década. Há assim que muitas vezes eu poderia ter usado isso! Não acredito que estou descobrindo agora.
precisa saber é o seguinte
1
Como isso se relaciona where?
Skia.heliou
4
Para responder à parte "where" da pergunta: Depois de receber o prompt pdb, (pdb) digite wheree ele imprimirá o rastreamento da pilha no terminal.
quer
1
O Python 3.7 e superior têm uma função interna breakpoint()que evita a necessidade de importar o pdb.
user650654
6

para quem precisa imprimir a pilha de chamadas enquanto usa o pdb, basta

(Pdb) where
rato ratazana
fonte
2

Aqui está uma variação da excelente resposta do @ RichieHindle, que implementa um decorador que pode ser aplicado seletivamente às funções conforme desejado. Funciona com o Python 2.7.14 e 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())

Saída da amostra:

test_func() called:
    File "stacktrace_decorator.py", line 28, in <module>
    print(test_func())
42
Martineau
fonte
Escrevi minha própria versão do decorador antes de ver isso. Votado.
Sida Zhou
0

Instale o Inspecione

pip3 install inspect-it --user

Código

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()])

você pode criar um trecho dessa linha

mostrará uma lista da pilha de chamadas de função com um nome de arquivo e um número de linha

lista do início até onde você coloca esta linha

MohitGhodasara
fonte