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

如何在Python中获取函数调用参数值及给定帧的参数原始值?

嘿,这个问题我刚好研究过,在Python里完全可以通过帧(frame)来获取函数调用的参数值,甚至能区分哪些是显式传入的,刚好适合做调试工具!下面给你详细讲怎么实现:

在Python中通过Frame获取函数调用参数的方案

核心思路

要解决这个问题,我们主要依靠Python的inspect模块,它能帮我们获取栈帧、函数签名、参数信息等关键内容。结合帧对象的f_locals、f_code等属性,就能还原出调用时的参数细节,包括区分显式传递的参数。

具体实现代码

下面是完善后的getCallParameter函数,不仅能返回包含参数值的字典,还能标记哪些是显式传入的参数(支持两种判断逻辑,兼顾简单性和准确性):

import inspect
import ast

def getCallParameter():
    # 获取调用栈,这里用stack[1]作为外层调用帧,你可以替换成自己的帧定位逻辑
    stack = inspect.stack()
    outer_frame = stack[1].frame
    try:
        # 获取目标函数的签名和帧内参数信息
        sig = inspect.signature(outer_frame.f_code)
        args_info = inspect.getargvalues(outer_frame)
        
        params = sig.parameters
        args = args_info.args
        varargs = args_info.varargs
        varkw = args_info.varkw
        locals_dict = args_info.locals
        
        # 初始化结果字典,存储每个参数的值和是否显式传入的标记
        result = {}
        
        # 第一步:获取所有参数的实际值
        arg_values = inspect.getcallargs(sig, *args_info.args, **(args_info.locals.get(varkw, {})))
        
        # 先基于默认值做基础判断(显式传入值等于默认值时会误判,后面会优化)
        for param_name, param in params.items():
            value = arg_values[param_name]
            is_explicit = True
            # 如果参数有默认值,先假设非显式,后面再修正
            if param.default is not inspect.Parameter.empty:
                is_explicit = False
            result[param_name] = {
                'value': value,
                'is_explicit': is_explicit
            }
        
        # 处理可变位置参数*args(全部是显式传入)
        if varargs:
            args_value = locals_dict.get(varargs, ())
            result[varargs] = {
                'value': args_value,
                'is_explicit': True
            }
        
        # 处理可变关键字参数**kwargs(全部是显式传入)
        if varkw:
            kwargs_value = locals_dict.get(varkw, {})
            result[varkw] = {
                'value': kwargs_value,
                'is_explicit': True
            }
        
        # 第二步:解析调用代码,更准确地标记显式传入的参数(即使值等于默认值)
        try:
            # 获取调用语句的代码上下文
            call_code = stack[1].code_context[0].strip()
            # 用AST解析调用表达式
            tree = ast.parse(call_code)
            call_node = tree.body[0].value
            if isinstance(call_node, ast.Call):
                # 收集显式传入的位置参数对应的参数名
                for idx, param_name in enumerate(args):
                    if idx < len(call_node.args):
                        result[param_name]['is_explicit'] = True
                # 收集显式传入的关键字参数名
                for kw_node in call_node.keywords:
                    if kw_node.arg in result:
                        result[kw_node.arg]['is_explicit'] = True
        except Exception:
            # 解析失败时(比如多行调用、复杂表达式),保留基础判断结果
            pass
        
        print("调用参数详情:", result)
        return result
    finally:
        # 必须删除栈引用,避免循环引用导致内存泄漏
        del stack

测试示例

我们用几个测试调用验证效果:

测试1:混合位置、关键字和可变参数

def test_func(a, b=10, *args, **kwargs):
    getCallParameter()

test_func(2, 4, 5, 6, x=100, y=200)

输出结果里,a、b、args、kwargs都会被标记为is_explicit: True,符合预期。

测试2:传入部分参数(含默认值)

test_func(2, x=100)

这里b用了默认值,会被标记为is_explicit: False,a和x(属于kwargs)是显式传入。

测试3:显式传入等于默认值的参数

test_func(2, 10)

通过AST解析,b虽然值等于默认值,但因为是显式位置传入,会被正确标记为is_explicit: True。

关键细节说明

  • 内存泄漏问题:必须在最后删除stack引用,因为栈帧会持有局部变量,不清理可能导致内存泄漏。
  • 两种判断逻辑:基础逻辑基于默认值对比,简单但有局限;AST解析逻辑能准确识别显式传入,即使值和默认值相同,但对复杂调用语句可能解析失败,所以做了异常处理。
  • 帧定位:你可以替换stack[1]为自己的帧定位逻辑,比如多层嵌套调用时的准确帧获取。

内容的提问来源于stack exchange,提问作者hl037_

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:50:18