获取关于参数的信息

先来看个关于HTTP微框架Bobo的例子

import bobo

@bobo.query('/')
def hello(person):
    return 'Hello %s!' % person

bobo.query 装饰器把一个普通的函数(如 hello)与框架的请求处理机制集成起来了。Bobo 会内省 hello 函数,发现它需要一个名为 person 的参数,然后从请求中获取那个名称对应的参数,将其传给 hello 函数
重点是,Bobo 是怎么知道函数需要哪个参数的呢?它又是怎么知道参数有没有默认值呢?
其实函数对象有个 defaults 属性,它的值是一个元组,里面保存着定位参数和关键字参数的默认值。仅限关键字参数的默认值在 kwdefaults 属性中。然而,参数的名称在 code 属性中,它的值是一个 code 对象引用,自身也有很多属性。
下面看一下提取关于函数参数的信息的示例

def tag(name, age=12, *content, cls=None, **attrs):
    x = 2
    pass

print(tag.__defaults__)
print(tag.__kwdefaults__)
print(tag.__code__.co_varnames)
print(tag.__code__.co_argcount)

"""
(12,)
{'cls': None}
('name', 'age', 'cls', 'content', 'attrs', 'x')
2
"""

参数名称在 __code__.co_varnames 中,不过里面还有函数定义体中创建的局部变量。
参数名称是前 N 个字符串,N 的值由 __code__.co_argcount 确定, 但是不包含前缀为 *** 的变长参数。
参数的默认值只能通过它们在 __defaults__ 元组中的位置确定,因此要从后向前扫描才能把参数和默认值对应起来。在这个示例中函数有两个参数(除了变长参数和仅限关键字参数),nameage,其中一个有默认值,即 12,因此它必然属于最后一个参数,即 age。
上面的实例看起来有些别扭,当然有更好的方式可以查看函数参数的信息,使用 inspect 模块

from inspect import signature

sig = signature(tag)

print(str(sig))

for name, param in sig.parameters.items():
    print(param.kind, ':', name, '=', param.default)

"""
(name, age=12, *content, cls=None, **attrs)
POSITIONAL_OR_KEYWORD : name = <class 'inspect._empty'>
POSITIONAL_OR_KEYWORD : age = 12
VAR_POSITIONAL : content = <class 'inspect._empty'>
KEYWORD_ONLY : cls = None
VAR_KEYWORD : attrs = <class 'inspect._empty'>
"""

inspect.signature 函数返回一个 inspect.Signature 对象,它有一个 parameters 属性,这是一个有序映射,把参数名和 inspect.Parameter 对象对应起来。各个 Parameter 属性也有自己的属性,例如 namedefaultkind。特殊的 inspect._empty 值表示没有默认值,考虑到 None 是有效的默认值(也经常这么做),而且这么做是合理的。

另外,inspect.Signature 对象有个 bind 方法,它可以把任意个参数绑定到签名中的形参上,所用的规则与实参到形参的匹配方式一样。框架可以使用这个方法在真正调用函数前验证参数。

sig = signature(tag)
my_tag = {'name': 'img', 'title': 'Cookbook', 'cls': 'framed'}

bound_args = sig.bind(**my_tag)
for name, value in bound_args.arguments.items():
    print(name, '=', value)
 
"""
name = img
cls = framed
attrs = {'title': 'Cookbook'}
"""

如果把必须指定的参数 namemy_tag 中删除,那么调用 sig.bind(**my_tag) 将会抛出 TypeError , 抱怨缺少 name 参数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容