inspect.signature() 返回signature对象,包含参数名、类型注解、默认值、可变参数标识、参数顺序及声明位置等结构化信息,需通过.parameters访问parameter实例获取具体字段。

inspect.signature() 能拿到什么信息?
inspect.signature() 返回的是 Signature 对象,不是字符串也不是字典,而是一个结构化描述——它包含所有参数名、类型注解、默认值、是否可变参数(*args / **kwargs)、参数顺序,甚至参数的声明位置(比如是位置参数还是仅关键字参数)。
常见错误是直接 print 它,结果看到一长串类似 <signature int b="1,"></signature> 的输出,误以为“拿到了”,其实这只是 repr;真正要用字段,得手动访问 .parameters。
-
.parameters是一个OrderedDict,key 是参数名,value 是Parameter实例 - 每个
Parameter有.name、.default(没默认值时为inspect.Parameter.empty)、.annotation(类型注解,也可能为inspect.Parameter.empty)、.kind(如Parameter.POSITIONAL_ONLY、Parameter.KEYWORD_ONLY等) - 注意:函数没写类型注解时,
.annotation就是inspect.Parameter.empty,别拿它当None判断
import inspect
<p>def example(a: int, b=1, *args, c: str = "hello", **kwargs):
pass</p><p>sig = inspect.signature(example)
for name, param in sig.parameters.items():
print(f"{name}: kind={param.kind}, default={param.default}, annotation={param.annotation}")</p>
如何安全提取参数名和默认值?
不能直接用 param.default 做逻辑判断,因为显式设为 None 和没设默认值都返回 inspect.Parameter.empty,但语义完全不同。
- 用
param.default is inspect.Parameter.empty判断是否“无默认值” - 用
param.annotation is not inspect.Parameter.empty判断是否有类型注解 - 如果要构建调用参数字典(比如做 mock 或自动填充),只取
kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY)的参数,跳过*args和**kwargs(它们没有独立名字)
def get_keyword_defaults(func):
sig = inspect.signature(func)
defaults = {}
for param in sig.parameters.values():
if param.kind in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY):
if param.default is not inspect.Parameter.empty:
defaults[param.name] = param.default
return defaults
为什么 inspect.getfullargspec() 有时会失效?
inspect.getfullargspec() 是旧接口,对带装饰器的函数经常失效——它不穿透装饰器,返回的可能是包装函数的参数,而不是原始函数的。而 inspect.signature() 默认会尝试用 <strong>wrapped</strong> 向下找,但前提是装饰器正确设置了该属性(比如用 @functools.wraps)。
- 没用
@functools.wraps的自定义装饰器,signature()也会卡在 wrapper 层 -
getfullargspec()还不支持typing.Literal、typing.Union等新注解,解析出来是typing.Union类型对象,不是字符串 - 遇到
TypeError: unsupported callable,大概率是传了 built-in 函数(如len、print),它们没有 Python 层源码,signature()只能靠 heuristics 推测,有时失败
实际用在装饰器里要注意什么?
想写一个“自动记录调用参数”的装饰器,不能只靠 signature() 抓定义,还得结合 *args、**kwargs 运行时传入的值做绑定。
- 用
sig.bind(*args, **kwargs)得到BoundArguments,再调.apply_defaults()才能补全所有默认值 -
bind()会校验参数合法性,如果传参错,它直接抛TypeError,不是静默忽略 - 不要直接修改
BoundArguments.arguments字典(它是浅拷贝),真要改用.arguments.copy()
def log_call(func):
sig = inspect.signature(func)
def wrapper(*args, **kwargs):
bound = sig.bind(*args, **kwargs)
bound.apply_defaults()
print("called with:", bound.arguments)
return func(*args, **kwargs)
return wrapper
参数绑定这一步绕不开,光看 signature 不等于知道这次调用具体传了什么。很多动态分析工具卡在这里——以为拿到 signature 就万事大吉,结果漏掉了实参映射逻辑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











