Wydrukuj bieżący stos wywołań z metody w kodzie Python

276

W Pythonie, jak mogę wydrukować bieżący stos wywołań z metody (w celu debugowania).

się
źródło

Odpowiedzi:

319

Oto przykład pobierania stosu przez moduł traceback i wydrukowania go:

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

Jeśli naprawdę chcesz wydrukować stos tylko na stderr, możesz użyć:

traceback.print_stack()

Lub, aby wydrukować na standardowe wyjście (przydatne, jeśli chcesz zachować przekierowane wyjście razem), użyj:

traceback.print_stack(file=sys.stdout)

Ale dzięki temu traceback.format_stack()możesz robić z nim, co chcesz.

RichieHindle
źródło
Jak zrobić to samo dla wszystkich innych wątków (mówię o wątkach, których nie kontroluję)  ?
user2284570,
Może coś tu brakuje, ale ty nazywasz f, którego jedynym celem jest wywołanie g i nic więcej nie robi. Dlaczego
Chris
6
@Chris: To tylko przykład. Ma wiele funkcji, aby wyjaśnić, że format_stack () drukuje wszystkie wywołania na stosie.
RichieHindle
Jeśli chcesz uzyskać więcej szczegółowych informacji wyjściowych (w tym vars itp.), Zobacz to powiązane pytanie i to .
Albert,
@ user2284570: Możesz użyć sys._current_frames(). Np. Py_better_exchook todump_all_thread_tracebacks robi (zrzeczenie się: Napisałem to).
Albert,
93
import traceback
traceback.print_stack()
Mark Roddy
źródło
8
Właściwie to podoba mi się to, traceback.print_exc()co daje ci prawie to samo, co otrzymałbyś bez tego exceptoświadczenia (i jest również mniej kodujące niż zaakceptowana odpowiedź).
martineau,
34
traceback.print_exc()wypisuje ślad stosu dla każdego wyjątku, który możesz obsługiwać - ale to nie rozwiązuje oryginalnego pytania, jak wydrukować bieżący stos („gdzie jesteś teraz” w przeciwieństwie do „gdzie twój kod był, kiedy poszedł ostatni wyjątek wyłączone, jeśli w ogóle ”.)
Tom Swirly
17

Jeśli używasz debugera Pythona, nie tylko interaktywne sondowanie zmiennych, ale możesz uzyskać stos wywołań za pomocą polecenia „where” lub „w”.

Więc na górze twojego programu

import pdb

Następnie w kodzie, w którym chcesz zobaczyć, co się dzieje

pdb.set_trace()

i pojawia się monit

Keir
źródło
2
Programuję w Pythonie od ponad dekady. Istnieje tak wiele razy mogłem użyć tego! Nie mogę uwierzyć, że właśnie się o tym dowiaduję.
hosford42
1
Jak się to odnosi where?
skia.heliou
4
Aby odpowiedzieć na część pytania „gdzie”: Po pojawieniu się monitu pdb (pdb) po prostu wpisz, wherea on wydrukuje ślad stosu do terminala.
stephenmm,
1
Python 3.7 i wyżej mają wbudowaną funkcję, breakpoint()która eliminuje potrzebę importowania pdb.
user650654
6

dla tych, którzy muszą wydrukować stos wywołań podczas korzystania z pdb, po prostu zrób

(Pdb) where
mysz szczur
źródło
2

Oto odmiana doskonałej odpowiedzi @ RichieHindle, która implementuje dekorator, który można selektywnie stosować do funkcji zgodnie z potrzebami. Działa z Python 2.7.14 i 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())

Dane wyjściowe z próbki:

test_func() called:
    File "stacktrace_decorator.py", line 28, in <module>
    print(test_func())
42
martineau
źródło
Napisałem własną wersję dekoratora, zanim to zobaczyłem. Pozytywne.
Sida Zhou,
0

Zainstaluj Inspect-it

pip3 install inspect-it --user

Kod

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

możesz zrobić fragment tej linii

pokaże ci listę stosów wywołań funkcji wraz z nazwą pliku i numerem linii

lista od początku do miejsca, w którym umieścisz ten wiersz

Mohit Ghodasara
źródło