In ngăn xếp cuộc gọi hiện tại từ một phương thức trong mã Python


276

Trong Python, làm cách nào tôi có thể in ngăn xếp cuộc gọi hiện tại từ trong một phương thức (cho mục đích gỡ lỗi).

Câu trả lời:


319

Dưới đây là một ví dụ về việc chồng qua traceback mô-đun, và in nó:

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

Nếu bạn thực sự chỉ muốn in ngăn xếp lên stderr, bạn có thể sử dụng:

traceback.print_stack()

Hoặc để in ra thiết bị xuất chuẩn (hữu ích nếu muốn giữ đầu ra được chuyển hướng cùng nhau), hãy sử dụng:

traceback.print_stack(file=sys.stdout)

Nhưng có được nó thông qua traceback.format_stack()cho phép bạn làm bất cứ điều gì bạn muốn với nó.


Làm thế nào để làm tương tự cho tất cả các luồng khác (Tôi đang nói về các luồng tôi không kiểm soát)  ?
dùng2284570

Có lẽ tôi đang thiếu một cái gì đó ở đây, nhưng bạn gọi f mà mục đích duy nhất của nó là ở đây là gọi g và không làm gì khác. Tại sao
Chris

6
@Chris: Đó chỉ là một ví dụ. Nó có nhiều chức năng để làm rõ rằng format_stack () in tất cả các cuộc gọi trên ngăn xếp.
RichieHulum

Nếu bạn muốn nhận được một số chi tiết tiết ra (bao gồm vars vv), xem câu hỏi có liên quan này , và cái này .
Albert

@ user2284570: Bạn có thể sử dụng sys._current_frames(). Ví dụ: py_better_exchookdump_all_thread_tracebacks làm điều đó (từ chối trách nhiệm: Tôi đã viết điều đó).
Albert

93
import traceback
traceback.print_stack()

8
Trên thực tế, tôi thích traceback.print_exc()cái mà cung cấp cho bạn gần như cùng một thứ mà bạn sẽ nhận được mà không cần excepttuyên bố (và cũng ít mã hóa hơn câu trả lời được chấp nhận).
martineau

34
traceback.print_exc()in dấu vết ngăn xếp cho bất kỳ ngoại lệ nào bạn có thể xử lý - nhưng điều này không giải quyết được câu hỏi ban đầu, đó là cách in ngăn xếp hiện tại ("bạn đang ở đâu" trái ngược với "mã của bạn ở đâu khi ngoại lệ cuối cùng đi tắt, nếu có ".)
Tom Swirly


17

Nếu bạn sử dụng trình gỡ lỗi python, không chỉ thăm dò các biến tương tác mà bạn có thể nhận được ngăn xếp cuộc gọi bằng lệnh "where" hoặc "w".

Vì vậy, ở đầu chương trình của bạn

import pdb

Sau đó, trong mã nơi bạn muốn xem những gì đang xảy ra

pdb.set_trace()

và bạn bị rơi vào một dấu nhắc


2
Tôi đã lập trình bằng Python được hơn một thập kỷ. Có rất nhiều lần tôi có thể đã sử dụng điều này! Tôi không thể tin rằng tôi vừa mới tìm hiểu về nó.
hosford42

1
Làm thế nào điều này liên quan đến where?
skia.heliou

4
Để trả lời phần "đâu" của câu hỏi: Sau khi bạn nhận được lời nhắc pdb, (pdb) chỉ cần gõ wherevà nó sẽ in dấu vết ngăn xếp đến thiết bị đầu cuối.
stephenmm

1
Python 3.7 trở lên có chức năng dựng sẵn breakpoint()mà không cần phải nhập pdb.
dùng650654

6

Đối với những người cần in ngăn xếp cuộc gọi trong khi sử dụng pdb, chỉ cần làm

(Pdb) where

2

Đây là một biến thể của câu trả lời xuất sắc của @ RichieHulum, trong đó thực hiện một trình trang trí có thể được áp dụng có chọn lọc cho các chức năng như mong muốn. Hoạt động với Python 2.7.14 và 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())

Đầu ra từ mẫu:

test_func() called:
    File "stacktrace_decorator.py", line 28, in <module>
    print(test_func())
42

Đã viết phiên bản trang trí của riêng tôi trước khi tôi nhìn thấy điều này. Nâng cao.
Sida Zhou

0

Cài đặt Kiểm tra-nó

pip3 install inspect-it --user

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

bạn có thể tạo một đoạn của dòng này

nó sẽ hiển thị cho bạn một danh sách ngăn xếp cuộc gọi hàm với tên tệp và số dòng

danh sách từ đầu đến nơi bạn đặt dòng này

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.