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

如何给装饰后的函数添加默认值并保留函数签名的参数与类型?

可以实现,以下是具体方案

你想要的是一个能给函数参数添加默认值,同时让类型检查工具和IDE识别到更新后参数签名的装饰器。原代码的问题在于装饰器返回的还是原函数的严格签名,所以类型检查会报错,下面是可行的实现方式:

核心思路

要实现这个需求需要解决两个关键点:

  1. 动态填充默认值:通过inspect模块获取原函数的参数信息,自动给指定参数补充默认值。
  2. 更新函数签名:修改函数的签名元数据,让类型检查工具(如mypy、PyCharm)识别到哪些参数现在是可选的(带默认值)。

完整实现代码

import inspect
import functools
from typing import Callable, ParamSpec, TypeVar

P = ParamSpec("P")
R = TypeVar("R")

def add_defaults(defaults: dict[str, any]) -> Callable[[Callable[P, R]], Callable[..., R]]:
    def decorator(f: Callable[P, R]) -> Callable[..., R]:
        # 获取原函数的参数签名
        original_sig = inspect.signature(f)
        params_list = list(original_sig.parameters.values())
        
        # 给指定参数添加默认值,生成新的参数列表
        new_params = []
        for param in params_list:
            if param.name in defaults:
                # 替换参数的默认值
                updated_param = param.replace(default=defaults[param.name])
                new_params.append(updated_param)
            else:
                new_params.append(param)
        
        # 创建新的函数签名
        new_sig = original_sig.replace(parameters=new_params)
        
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            # 绑定参数并自动填充默认值
            bound_args = new_sig.bind(*args, **kwargs)
            bound_args.apply_defaults()
            # 调用原函数
            return f(*bound_args.args, **bound_args.kwargs)
        
        # 给wrapper设置新的签名,让IDE和类型检查工具识别
        wrapper.__signature__ = new_sig
        return wrapper
    return decorator

使用示例

@add_defaults({"b": 0})
def my_func(a: str, b: int):
    print(f"a: {a}, b: {b}")

# 现在可以正常调用,b使用默认值0
my_func("a")
# 也可以传入指定值
my_func("hello", 10)

关键细节说明

  • inspect.signature:用来提取原函数的参数结构,包括参数名、类型、是否有默认值等信息。
  • functools.wraps:保留原函数的元数据(如函数名、文档字符串),避免装饰器掩盖原函数的基本信息。
  • __signature__属性:手动设置这个属性后,IDE和类型检查工具会使用新的签名进行校验,不会再提示参数缺失。
  • bind和apply_defaults:自动处理位置参数和关键字参数的绑定,无需手动拼接参数字典,逻辑更简洁可靠。

类型注解优化(可选)

如果需要更精确的类型提示,可以结合PEP 612的Concatenate和overload来完善装饰器的类型注解,让类型检查工具能更准确识别参数变化:

from typing import overload, Concatenate

@overload
def add_defaults(defaults: dict[str, any]) -> Callable[[Callable[P, R]], Callable[Concatenate[P.args, P.kwargs], R]]:
    ...

# 后续的decorator实现和之前一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 17:37:20