Jarvis' Blog 总有美丽的风景让人流连

Python库函数 (四) inspect

2021-06-04
Jarvis
Wiki_Python

简介

Python 中的 inspect 模块提供了一些有用的函数帮助获取对象的信息,例如模块、类、方法、函数、堆栈追踪、帧对象以及代码对象. 比如, 它可以辅助检查类的内容, 获取某个方法的源码, 获取并格式化某个函数的参数列表, 或者获取堆栈追踪的详细信息.

inspect.signiture

  • inspect.signiture
  • inspect.Parameter

该方法可以获取函数的签名.

1
2
3
4
5
6
7
8
9
import inspect

def foo(a, *args, b: int=1, c=(2, 3), d="4", **kwargs):
	pass

sig = inspect.signature(foo)

for n, p in sig.parameters.items():
	print(type(p), p.name, p.kind, p.annotation, p.default)

输出结果为

1
2
3
4
5
6
<class 'inspect.Parameter'> a POSITIONAL_OR_KEYWORD <class 'inspect._empty'> <class 'inspect._empty'>
<class 'inspect.Parameter'> args VAR_POSITIONAL <class 'dict'> <class 'inspect._empty'>
<class 'inspect.Parameter'> b KEYWORD_ONLY <class 'int'> 1
<class 'inspect.Parameter'> c KEYWORD_ONLY <class 'inspect._empty'> (2, 3)
<class 'inspect.Parameter'> d KEYWORD_ONLY <class 'inspect._empty'> 4
<class 'inspect.Parameter'> kwargs VAR_KEYWORD <class 'inspect._empty'> <class 'inspect._empty'>

可以发现, inspect 模块把参数表示为 inspect.Parameter 的实例. 参数的 kind 表示参数类型, 共有五种:

  • POSITIONAL_OR_KEYWORD: 表示该参数既可以是定位参数, 也可以是关键字参数
  • VAR_POSITIONAL: 多个位置参数, 通常是 *args
  • VAR_KEYWORD: 多个关键字参数, 通常是 **kwargs
  • KEYWORD_ONLY: 必须是关键字参数, 表示那些在 *args 后面的参数, 必须通过关键字提供
  • POSITIONAL_ONLY: 必须是定位参数, 用户遇不到这种需求, python 的一些古老的内置函数包含这种类型的参数, 比如 pow.

下面的函数可以获取函数的所有参数(Ref). 该函数返回函数的 (1)所有参数名的列表, (2) 可变定位参数名, (3) 可变关键字参数名, (4) 定位参数名的列表, (5) 关键字参数的字典.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def get_argspec(f):
    sig = inspect.signature(f)
    args = [n for n, p in sig.parameters.items() if p.kind in ARG_TYPES]
    pos_args = [
        n
        for n, p in sig.parameters.items()
        if p.kind in POSARG_TYPES and p.default == inspect._empty
    ]
    varargs = [
        n for n, p in sig.parameters.items() if p.kind == Parameter.VAR_POSITIONAL
    ]
    # only use first vararg  (how on earth would you have more anyways?)
    vararg_name = varargs[0] if varargs else None

    varkws = [n for n, p in sig.parameters.items() if p.kind == Parameter.VAR_KEYWORD]
    # only use first varkw  (how on earth would you have more anyways?)
    kw_wildcard_name = varkws[0] if varkws else None
    kwargs = OrderedDict(
        [
            (n, p.default)
            for n, p in sig.parameters.items()
            if p.default != inspect._empty
        ]
    )

    return args, vararg_name, kw_wildcard_name, pos_args, kwargs

Content