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

函数间传递kwargs时,如何打印其内部设置的默认值

问题根源

你的装饰器只能从函数签名中提取参数默认值,但n_remove=0是在函数内部通过kwargs.get()设置的逻辑,不属于函数签名的一部分,所以装饰器无法自动识别这些隐式的默认值。


解决方案

方案1:显式声明kwargs参数到函数签名(推荐)

把函数内部用到的kwargs参数显式写到函数签名里并设置默认值,这样inspect模块就能直接识别到,装饰器可以轻松打印出所有参数的最终取值。

修改后的完整代码:

from functools import wraps
import inspect

def print_kwargs(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling function {func.__name__}")
        
        # 打印传入的关键字参数
        if kwargs:
            print("Passed keyword arguments:")
            for key, value in kwargs.items():
                print(f"  {key} = {value}")

        # 绑定参数并填充默认值,打印所有参数的最终取值
        sig = inspect.signature(func)
        bound_args = sig.bind(*args, **kwargs)
        bound_args.apply_defaults()
        print("Final argument values:")
        for key, value in bound_args.arguments.items():
            print(f"  {key} = {value}")

        return func(*args, **kwargs)
    return wrapper

@print_kwargs
def fun1(a, n_remove=0, **kwargs):
    b = fun2(a[n_remove:], n_remove=n_remove, **kwargs)
    return b

@print_kwargs
def fun2(x, n_remove=0, **kwargs):
    return x

效果

  • 调用fun1([1,2,3])时,会打印n_remove = 0
  • 调用fun1([1,2,3], n_remove=1)时,两个函数的n_remove取值都会被打印

优缺点

  • ✅ 简单直观,依赖标准库inspect的参数绑定功能,稳定可靠
  • ❌ 需要修改函数定义,把内部用到的kwargs参数显式提出来

方案2:通过函数属性声明内部kwargs默认值

如果不想修改函数签名,可以给每个函数添加一个属性,存储内部用到的kwargs默认值,装饰器读取这个属性来打印实际取值。

完整代码:

from functools import wraps
import inspect

def print_kwargs(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling function {func.__name__}")
        
        # 打印传入的关键字参数
        if kwargs:
            print("Passed keyword arguments:")
            for key, value in kwargs.items():
                print(f"  {key} = {value}")

        # 打印函数内部声明的kwargs默认值
        if hasattr(func, 'internal_kwargs_defaults'):
            print("Internal kwargs defaults:")
            for key, default_val in func.internal_kwargs_defaults.items():
                actual_val = kwargs.get(key, default_val)
                print(f"  {key} = {actual_val} (default: {default_val})")

        return func(*args, **kwargs)
    return wrapper

@print_kwargs
def fun1(a, **kwargs):
    n_remove = kwargs.get('n_remove', 0)
    b = fun2(a[n_remove:], **kwargs)
    return b
# 给函数添加内部默认值属性
fun1.internal_kwargs_defaults = {'n_remove': 0}

@print_kwargs
def fun2(x, **kwargs):
    return x
fun2.internal_kwargs_defaults = {'n_remove': 0}

效果

  • 调用fun1([1,2,3])时,会打印n_remove = 0 (default: 0)
  • 调用fun1([1,2,3], n_remove=1)时,会打印n_remove = 1 (default: 0)

优缺点

  • ✅ 无需修改函数签名,保持原参数结构
  • ❌ 需要手动给每个函数添加属性,容易遗漏

方案3:解析函数源代码提取默认值(进阶)

如果不想手动声明,可以通过ast模块解析函数源代码,自动提取kwargs.get(key, default)中的键和默认值。这种方法依赖代码格式,但适合批量处理场景。

完整代码:

from functools import wraps
import inspect
import ast

def extract_kwargs_get_defaults(func):
    """解析函数源代码,提取kwargs.get(key, default)的键和默认值"""
    source = inspect.getsource(func)
    tree = ast.parse(source)
    defaults = {}
    
    # 遍历函数体内的所有节点
    for node in ast.walk(tree):
        # 匹配kwargs.get()的调用
        if (isinstance(node, ast.Call) 
            and isinstance(node.func, ast.Attribute) 
            and node.func.attr == 'get'
            and isinstance(node.func.value, ast.Name) 
            and node.func.value.id == 'kwargs'):
            if len(node.args) >= 1:
                key = ast.literal_eval(node.args[0])
                default = ast.literal_eval(node.args[1]) if len(node.args) >=2 else None
                defaults[key] = default
    return defaults

def print_kwargs(func):
    internal_defaults = extract_kwargs_get_defaults(func)
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling function {func.__name__}")
        
        # 打印传入的关键字参数
        if kwargs:
            print("Passed keyword arguments:")
            for key, value in kwargs.items():
                print(f"  {key} = {value}")

        # 打印解析到的内部默认值
        if internal_defaults:
            print("Internal kwargs defaults (parsed):")
            for key, default_val in internal_defaults.items():
                actual_val = kwargs.get(key, default_val)
                print(f"  {key} = {actual_val} (default: {default_val})")

        return func(*args, **kwargs)
    return wrapper

@print_kwargs
def fun1(a, **kwargs):
    n_remove = kwargs.get('n_remove', 0)
    b = fun2(a[n_remove:], **kwargs)
    return b

@print_kwargs
def fun2(x, **kwargs):
    foo = kwargs.get('foo', 'bar')
    return x

效果

自动解析出fun1的n_remove=0和fun2的foo='bar'并打印实际取值

优缺点

  • ✅ 无需手动修改函数或添加属性,自动识别
  • ❌ 依赖代码格式(必须是kwargs.get(key, default)的写法),复杂表达式或嵌套场景会解析失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 09:10:52