杰瑞科技汇

Python stack tracker如何追踪调用栈?

Of course! A "Python stack tracker" can mean a few different things. I'll cover the most common and useful interpretations, from simple built-in tools to powerful external libraries.

Python stack tracker如何追踪调用栈?-图1
(图片来源网络,侵删)

Here's a breakdown of the best ways to track and understand the "stack" in Python:


The Simple & Built-in: traceback Module

This is the fundamental way to inspect the call stack, especially when an exception occurs. It's part of the standard library, so you don't need to install anything.

Use Case: When an Error Happens

When your code crashes, Python automatically prints a traceback. This is the stack tracker in its most basic form.

# file: my_app.py
def function_b():
    # This line will cause a ZeroDivisionError
    return 10 / 0
def function_a():
    # We call function_b from here
    result = function_b()
    print(f"The result is: {result}")
if __name__ == "__main__":
    function_a()

Running this code produces the following traceback:

Python stack tracker如何追踪调用栈?-图2
(图片来源网络,侵删)
Traceback (most recent call last):
  File "my_app.py", line 10, in <module>
    function_a()
  File "my_app.py", line 7, in function_a
    result = function_b()
  File "my_app.py", line 3, in function_b
    return 10 / 0
ZeroDivisionError: division by zero

How to read it:

  • It reads from bottom to top.
  • The bottom is the origin of the error (ZeroDivisionError).
  • Each level above shows the function call that led to the error, along with the file name and line number.

Programmatic Use of traceback

You can capture the traceback as a string or a list of frames to log it, send it to a monitoring service, or print it in a custom format.

import traceback
import sys
def function_c():
    raise ValueError("Something went wrong in C!")
def function_b():
    function_c()
def function_a():
    try:
        function_b()
    except Exception:
        # Get the traceback as a string
        tb_str = traceback.format_exc()
        print("--- Caught Exception ---")
        print(tb_str)
        # Get the traceback as a list of FrameSummary objects
        tb_list = traceback.extract_tb(sys.exc_info()[2])
        print("\n--- Frame Summary ---")
        for frame_summary in tb_list:
            print(f"File: {frame_summary.filename}")
            print(f"  Line: {frame_summary.lineno}")
            print(f"  Function: {frame_summary.name}")
            print(f"  Code: {frame_summary.line}")
if __name__ == "__main__":
    function_a()

Output:

--- Caught Exception ---
Traceback (most recent call last):
  File "my_app.py", line 20, in function_a
    function_b()
  File "my_app.py", line 16, in function_b
    function_c()
  File "my_app.py", line 12, in function_c
    raise ValueError("Something went wrong in C!")
ValueError: Something went wrong in C!
--- Frame Summary ---
File: my_app.py
  Line: 20
  Function: function_a
  Code:         function_b()
File: my_app.py
  Line: 16
  Function: function_b
  Code:         function_c()
File: my_app.py
  Line: 12
  Function: function_c
  Code:     raise ValueError("Something went wrong in C!")

For Debugging: pdb (Python Debugger)

The pdb module is an interactive source code debugger. It's the most powerful tool for stepping through your code line-by-line and inspecting the stack and variables at any point.

Python stack tracker如何追踪调用栈?-图3
(图片来源网络,侵删)

Use Case: Interactive Debugging

Let's use the same code as before.

# file: my_app.py
def function_b():
    print("Inside function_b, about to crash...")
    return 10 / 0
def function_a():
    print("Calling function_b from function_a")
    result = function_b()
    print(f"The result is: {result}")
if __name__ == "__main__":
    function_a()

How to use pdb:

  1. Set a breakpoint: You can do this by adding import pdb; pdb.set_trace() in your code.
  2. Run the script: python my_app.py
  3. Interact with the debugger: The execution will pause at the breakpoint.
$ python my_app.py
> my_app.py(14, in <module>()
-> function_a()
(Pdb) n
Calling function_b from function_a
> my_app.py(10, in function_a()
-> result = function_b()
(Pdb) n
Inside function_b, about to crash...
> my_app.py(4, in function_b()
-> return 10 / 0
(Pdb) w
  my_app.py(14, in <module>()
-> function_a()
  my_app.py(10, in function_a()
-> result = function_b()
> my_app.py(4, in function_b()
-> return 10 / 0
(Pdb) l
  1     import pdb
  2
  3     def function_b():
  4  ->     print("Inside function_b, about to crash...")
  5         return 10 / 0
  6
  7     def function_a():
  8         print("Calling function_b from function_a")
  9         result = function_b()
 10         print(f"The result is: {result}")
 11
 12     if __name__ == "__main__":
 13         function_a()
 14  ->     function_a()
[EOF]
(Pdb) c
Traceback (most recent call last):
  File "my_app.py", line 14, in <module>
    function_a()
  File "my_app.py", line 10, in function_a
    result = function_b()
  File "my_app.py", line 5, in function_b
    return 10 / 0
ZeroDivisionError: division by zero

Key pdb commands for stack tracking:

  • w (where): Shows the current stack trace, highlighting the current frame.
  • u (up): Moves your context up the call stack (to the caller).
  • d (down): Moves your context down the call stack (to the callee).
  • l (list): Shows the source code around the current line.
  • n (next): Executes the current line and moves to the next one in the same function.
  • s (step): Executes the current line and steps into any function call.
  • c (continue): Continues execution until the next breakpoint or the program finishes.

For Production Monitoring: Sentry

If you're building a real application, you need a way to track errors in production. Services like Sentry are designed for this. They automatically capture and report uncaught exceptions, including the full stack trace, along with environment data (OS, Python version, installed packages, etc.).

This is the most robust and scalable solution.

How it Works (Conceptual)

  1. Install the Sentry SDK:

    pip install sentry-sdk
  2. Initialize Sentry in your app:

    import sentry_sdk
    from sentry_sdk.integrations.logging import LoggingIntegration
    # Configure the SDK
    sentry_sdk.init(
        dsn="YOUR_PUBLIC_DSN_HERE", # Get this from your Sentry project
        integrations=[LoggingIntegration(level=logging.INFO, event_level=logging.WARNING)],
        traces_sample_rate=1.0,
    )
  3. Run your app. Sentry will automatically catch any unhandled exceptions and send the full stack trace to your Sentry dashboard.

You get a beautiful, searchable interface to analyze your errors, group them, and see the full context of what went wrong.


For Performance Profiling: cProfile

Sometimes you don't care about what went wrong, but where your program is spending its time. The cProfile module is a built-in profiler that tracks function calls and how much time is spent in each part of the stack.

Use Case: Finding Performance Bottlenecks

# file: slow_code.py
import time
def fast_function():
    for _ in range(100):
        pass
def slow_function():
    time.sleep(0.5) # Simulate a slow operation
def medium_function():
    for _ in range(1000):
        fast_function()
    slow_function()
if __name__ == "__main__":
    for _ in range(5):
        medium_function()

How to run cProfile:

python -m cProfile -s tottime slow_code.py

Output (simplified):


         4 function calls in 2.505 seconds
   Ordered by: internal time
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        5    2.505    0.501    2
分享:
扫描分享到社交APP
上一篇
下一篇