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

如何用inspect.signature检查函数仅需一个位置参数?

运行时校验函数是否可接受单个位置参数

问题背景

需要在运行时校验传入的函数是否可以接受单个位置参数(该参数为字符串,函数返回真值)。最初的实现通过检查参数数量是否为1来判断,但无法兼容支持*args和**kwargs的函数——这类函数明明可以正常接收1个位置参数,却被误判为不合法。

初始实现代码:

from inspect import signature
from typing import Callable

def check(v_in : Callable):
    """check that the function can be called with 1 positional parameter supplied"""
    sig = signature(v_in)
    len_param = len(sig.parameters)
    if not len_param == 1:
        raise ValueError(
            f"expecting 1 parameter, of type `str` for {v_in}.  got {len_param}"
        )
    return v_in

解决方案

方法1:利用inspect.signature.bind做实际参数绑定校验

这是最直接可靠的方法,直接模拟调用时的参数绑定逻辑,只要能成功绑定单个位置参数,就说明函数符合要求,无需手动分析参数类型。

from inspect import signature

def check(v_in):
    """校验函数是否可接受单个位置参数调用"""
    sig = signature(v_in)
    try:
        # 尝试绑定一个测试字符串作为位置参数
        sig.bind("test_input")
    except TypeError as e:
        raise ValueError(f"函数 {v_in} 无法接受单个位置参数调用:{e}") from e
    return v_in

这个方法能覆盖所有合法场景:

  • 单参数函数(def f(a): ...)
  • 带*args的函数(def f(*args): ...)
  • 含默认值参数的函数(def f(a=None): ...)
  • 混合参数但可接受单个位置参数的函数(def f(a, *args): ...)

同时会正确拦截非法场景:

  • 需要多个必填位置参数的函数(def f(a, b): ...)
  • 仅支持关键字参数的函数(def f(*, a): ...)

方法2:手动分析参数类型与必填性

如果需要更精细的控制,可以通过遍历参数的kind属性和默认值,判断函数是否满足要求:

from inspect import signature, Parameter

def check(v_in):
    sig = signature(v_in)
    params = list(sig.parameters.values())
    
    required_positional = 0
    has_var_positional = False
    has_positional_slot = False

    for param in params:
        if param.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD):
            has_positional_slot = True
            # 统计无默认值的必填位置参数
            if param.default is Parameter.empty:
                required_positional += 1
        elif param.kind == Parameter.VAR_POSITIONAL:
            has_var_positional = True

    # 无任何可接收位置参数的途径(全关键字参数)
    if not has_positional_slot and not has_var_positional:
        raise ValueError(f"函数 {v_in} 无法接收任何位置参数")
    # 必填位置参数超过1个,无法仅传单个位置参数调用
    if required_positional > 1:
        raise ValueError(f"函数 {v_in} 至少需要 {required_positional} 个位置参数,不符合要求")
    
    return v_in

关于typing.Protocol的说明

Protocol是用于静态类型检查的工具,Python运行时不会强制校验函数是否符合Protocol定义,因此无法直接用它做运行时的参数校验。如果需要结合类型提示和运行时校验,可以考虑第三方库,但标准库层面无法实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:45:37