Python2.7中如何不调用函数检查*args与**kwargs是否匹配函数签名?
先看你的问题:
给定函数定义:
def f(a, b, *args, kw_a=None, kw_b=123, **kwargs): ...请问是否存在简便方法,无需实际调用该函数,即可检查给定的
args和kwargs能否满足调用f(*args, **kwargs)?
已知Python3.3及以上版本提供了inspect.Signature.bind()方法,那Python2.7中有没有比使用inspect.getargspec()并解析返回的ArgSpec元组更简便的方案?
Python3.3+ 的简便方案
确实,inspect.Signature.bind()就是专门干这个事的,完全不需要实际调用函数,只需要对函数签名做参数绑定验证就行。
具体步骤很简单:
- 用
inspect.signature()获取函数的签名对象 - 调用签名对象的
bind(*args, **kwargs)方法 - 如果绑定成功,说明参数合法;如果参数不匹配,会直接抛出
TypeError,和实际调用函数时的错误一致
举个实际例子:
import inspect def f(a, b, *args, kw_a=None, kw_b=123, **kwargs): pass # 合法参数验证 args_valid = (1, 2, 3, 4) kwargs_valid = {"kw_a": "test", "extra": "foo"} try: sig = inspect.signature(f) sig.bind(*args_valid, **kwargs_valid) print("参数合法") except TypeError as e: print(f"参数不合法: {e}") # 非法参数验证(缺少必填的b参数) args_invalid = (1,) try: sig.bind(*args_invalid) except TypeError as e: print(f"参数不合法: {e}")
这个方法完全不会触发函数体的执行,完美解决你的第一个问题。
Python2.7 的替代方案
Python2.7原生的inspect模块没有Signature相关功能,如果你不想手动啃inspect.getargspec()返回的元组(要处理位置参数、可变参数、关键字参数一堆逻辑,确实麻烦),有个更省心的第三方库可选——funcsigs。
这个库是Python3.3+ inspect模块签名功能的向后兼容实现,专门给Python2.6-2.7用的,用法和Python3的inspect.Signature几乎完全一致。
使用步骤:
- 先安装库:
pip install funcsigs - 然后就可以用和Python3一样的方式做参数绑定验证:
from funcsigs import signature def f(a, b, *args, kw_a=None, kw_b=123, **kwargs): pass # 验证参数 args_to_check = (1, 2) kwargs_to_check = {"kw_b": 456} try: sig = signature(f) sig.bind(*args_to_check, **kwargs_to_check) print("参数合法") except TypeError as e: print(f"参数不合法: {e}")
如果不想用第三方库,退而求其次的方法是用mock替换原函数的实现,再尝试调用——这样即使原函数有副作用(比如写文件、发请求),也不会执行实际逻辑:
from mock import Mock def f(a, b, *args, kw_a=None, kw_b=123, **kwargs): # 假设这个函数有副作用 with open("test.txt", "w") as f: f.write("something") # 用原函数的签名约束Mock mock_f = Mock(spec=f) try: mock_f(*(1,2), **{"kw_a": "test"}) print("参数合法") except TypeError as e: print(f"参数不合法: {e}")
不过这个方法不如funcsigs可靠,Mock的参数检查偶尔会有疏漏,所以优先推荐funcsigs,这绝对比手动解析ArgSpec简便多了。
内容的提问来源于stack exchange,提问作者Błażej Michalik

