You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在每条Python语句执行后自动调用指定函数?

实现Python语句后自动执行指定函数的方法

可以实现,以下是几种无需手动逐行添加调用的实用方案:

1. 使用sys.settrace()跟踪代码执行

Python的sys.settrace()能设置跟踪函数,在代码执行的不同阶段触发回调。我们可以利用它在每条语句执行完成后调用目标函数。

示例代码:

import sys

def after_statement():
    print("这条语句执行完了!")

def trace_func(frame, event, arg):
    # 只响应语句执行完成的事件
    if event == 'line':
        after_statement()
    return trace_func

# 启动全局跟踪
sys.settrace(trace_func)

# 测试代码
a = 1 + 2
print(a)
b = "hello"

注意:该方法会对全局代码生效(包括标准库语句),存在一定性能开销,更适合调试或小范围场景使用。

2. 用AST修改代码自动插入调用

通过Python的ast模块解析代码的抽象语法树,在每个语句节点后插入调用目标函数的节点,再编译执行修改后的AST。这种方式更精准,不会干扰无关代码。

示例代码:

import ast
import inspect

def after_statement():
    print("语句执行完成")

class InsertCallVisitor(ast.NodeTransformer):
    def visit_Expr(self, node):
        # 在每个表达式语句后插入调用节点
        call_node = ast.Call(
            func=ast.Name(id='after_statement', ctx=ast.Load()),
            args=[],
            keywords=[]
        )
        return ast.Block([node, ast.Expr(value=call_node)])
    
    def visit_Assign(self, node):
        # 在赋值语句后插入调用节点
        call_node = ast.Call(
            func=ast.Name(id='after_statement', ctx=ast.Load()),
            args=[],
            keywords=[]
        )
        return ast.Block([node, ast.Expr(value=call_node)])

def auto_call_after_statements(func):
    # 获取函数源代码并解析为AST
    source = inspect.getsource(func)
    tree = ast.parse(source)
    # 遍历修改AST
    visitor = InsertCallVisitor()
    modified_tree = visitor.visit(tree)
    ast.fix_missing_locations(modified_tree)
    # 编译执行修改后的代码
    exec(compile(modified_tree, filename='<ast>', mode='exec'), globals(), locals())
    return locals()[func.__name__]

# 测试用函数
@auto_call_after_statements
def test_func():
    x = 10
    y = x * 2
    print(y)

test_func()

这种方法适合针对特定函数内的语句处理,不会影响全局代码,性能损耗更小。

3. 字节码层面注入调用(进阶)

通过修改函数的代码对象,在字节码层面插入调用目标函数的指令。这种方式较为底层,需要了解Python字节码知识,适合对性能要求较高的场景。

示例代码(简化版):

import types
import dis

def after_statement():
    print("语句执行完了")

def inject_call(func):
    original_code = func.__code__
    # 生成调用after_statement的字节码指令
    # LOAD_GLOBAL after_statement -> CALL_FUNCTION 0 -> POP_TOP
    call_bytes = b'\x64\x00\x00\x83\x00\x00\x01'
    # 合并原字节码与新指令(实际需按语句拆分插入,此处为简化示例)
    new_code = types.CodeType(
        original_code.co_argcount,
        original_code.co_posonlyargcount,
        original_code.co_kwonlyargcount,
        original_code.co_nlocals,
        original_code.co_stacksize + 2,
        original_code.co_flags,
        original_code.co_code + call_bytes,
        original_code.co_consts,
        original_code.co_names + ('after_statement',),
        original_code.co_varnames,
        original_code.co_filename,
        original_code.co_name,
        original_code.co_firstlineno,
        original_code.co_lnotab,
        original_code.co_freevars,
        original_code.co_cellvars
    )
    func.__code__ = new_code
    return func

# 测试
@inject_call
def test():
    a = 5
    print(a)

test()

注意:字节码指令依赖Python版本,不同版本可能存在差异,维护成本较高。

内容的提问来源于stack exchange,提问作者T. F.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 01:55:18