inspect --- 检查对象

源代码: Lib/inspect.py


inspect 模块提供了一些有用的函数帮助获取对象的信息,例如模块、类、方法、函数、回溯、帧对象以及代码对象。例如它可以帮助你检查类的内容,获取某个方法的源代码,取得并格式化某个函数的参数列表,或者获取你需要显示的回溯的详细信息。

该模块提供了4种主要的功能:类型检查、获取源代码、检查类与函数、检查解释器的调用堆栈。

类型和成员

getmembers() 函数获取对象的成员,例如类或模块。函数名以"is"开始的函数主要作为 getmembers() 的第2个参数使用。它们也可用于判定某对象是否有如下的特殊属性:

类型

属性

描述

module

__doc__

文档字符串

__file__

文件名(内置模块没有文件名)

class

__doc__

文档字符串

__name__

类定义时所使用的名称

__qualname__

qualified name -- 限定名称

__module__

该类型被定义时所在的模块的名称

method -- 方法

__doc__

文档字符串

__name__

该方法定义时所使用的名称

__qualname__

qualified name -- 限定名称

__func__

实现该方法的函数对象

__self__

该方法被绑定的实例,若没有绑定则为 None

__module__

定义此方法的模块的名称

function -- 函数

__doc__

文档字符串

__name__

用于定义此函数的名称

__qualname__

qualified name -- 限定名称

__code__

包含已编译函数的代码对象 bytecode

__defaults__

所有位置或关键字参数的默认值的元组

__kwdefaults__

保存仅关键字参数的所有默认值的映射

__globals__

此函数定义所在的全局命名空间

__annotations__

参数名称到注解的映射;保留键 "return" 用于返回值注解。

__module__

此函数定义所在的模块名称

回溯

tb_frame

此层的帧对象

tb_lasti

在字节码中最后尝试的指令的索引

tb_lineno

当前行在 Python 源代码中的行号

tb_next

下一个内部回溯对象(由本层调用)

frame -- 帧

f_back

下一个外部帧对象(此帧的调用者)

f_builtins

此帧执行时所在的 builtins 命名空间

f_code

在此帧中执行的代码对象

f_globals

此帧执行时所在的全局命名空间

f_lasti

在字节码中最后尝试的指令的索引

f_lineno

当前行在 Python 源代码中的行号

f_locals

此帧所看到的局部命名空间

f_trace

此帧的追踪函数,或 None

code

co_argcount

参数数量(不包括仅关键字参数、* 或 ** 参数)

co_code

字符串形式的原始字节码

co_cellvars

单元变量名称的元组(通过包含作用域引用)

co_consts

字节码中使用的常量元组

co_filename

创建此代码对象的文件的名称

co_firstlineno

第一行在Python源代码中的行号

co_flags

CO_* 标志的位图,详见 此处

co_lnotab

编码的行号到字节码索引的映射

co_freevars

自由变量的名字组成的元组(通过函数闭包引用)

co_posonlyargcount

仅限位置参数的数量

co_kwonlyargcount

仅限关键字参数的数量(不包括 ** 参数)

co_name

定义此代码对象的名称

co_names

局部变量名称的元组

co_nlocals

局部变量的数量

co_stacksize

需要虚拟机堆栈空间

co_varnames

参数名和局部变量的元组

generator -- 生成器

__name__

name

__qualname__

qualified name -- 限定名称

gi_frame

frame -- 帧

gi_running

生成器在运行吗?

gi_code

code

gi_yieldfrom

通过 yield from``迭代的对象,或``None

coroutine -- 协程

__name__

name

__qualname__

qualified name -- 限定名称

cr_await

正在等待的对象,或 None

cr_frame

frame -- 帧

cr_running

这个协程正在运行吗?

cr_code

code

cr_origin

协程被创建的位置,或 None。参见 sys.set_coroutine_origin_tracking_depth()

builtin

__doc__

文档字符串

__name__

此函数或方法的原始名称

__qualname__

qualified name -- 限定名称

__self__

方法绑定到的实例,或 None

在 3.5 版更改: 为生成器添加 __qualname__gi_yieldfrom 属性。

生成器的 __name__ 属性现在由函数名称设置,而不是代码对象名称,并且现在可以被修改。

在 3.7 版更改: 为协程添加 cr_origin 属性。

inspect.getmembers(object[, predicate])

返回一个对象上的所有成员,组成以 (名称, 值) 对为元素的列表,按名称排序。如果提供了可选的 predicate 参数(会对每个成员的 对象进行一次调用),则仅包含该断言为真的成员。

注解

如果要让 getmembers() 返回元类中定义的类属性,那么实参须为一个类且这些属性在元类的自定义方法 __dir__() 中列出。

inspect.getmodulename(path)

返回由文件名 path 表示的模块名字,但不包括外层的包名。文件扩展名会检查是否在 importlib.machinery.all_suffixes() 列出的条目中。如果符合,则文件路径的最后一个组成部分会去掉后缀名后被返回;否则返回 None

值得注意的是,这个函数 返回可以作为 Python 模块的名字,而有可能指向一个 Python 包的路径仍然会返回 None

在 3.3 版更改: 该函数直接基于 importlib

inspect.ismodule(object)

当该对象是一个模块时返回 True

inspect.isclass(object)

当该对象是一个类时返回 True,无论是内置类或者 Python 代码中定义的类。

inspect.ismethod(object)

当该对象是一个 Python 写成的绑定方法时返回 True

inspect.isfunction(object)

当该对象是一个 Python 函数时(包括使用 lambda 表达式创造的函数),返回 True

inspect.isgeneratorfunction(object)

当该对象是一个 Python 生成器函数时返回 True

在 3.8 版更改: 对于使用 functools.partial() 封装的函数,如果被封装的函数是一个 Python 生成器函数,现在也会返回 True

inspect.isgenerator(object)

当该对象是一个生成器时返回 True

inspect.iscoroutinefunction(object)

当该对象是一个 协程函数 (通过 async def 语法定义的函数)。

3.5 新版功能.

在 3.8 版更改: 对于使用 functools.partial() 封装的函数,如果被封装的函数是一个 协程函数 ,现在也会返回 True

inspect.iscoroutine(object)

当该对象是一个由 async def 函数创建的 协程 时返回 True

3.5 新版功能.

inspect.isawaitable(object)

如果该对象可以在 await 表达式中使用时返回 True

也可以用于区分基于生成器的协程和常规的生成器:

def gen():
    yield
@types.coroutine
def gen_coro():
    yield

assert not isawaitable(gen())
assert isawaitable(gen_coro())

3.5 新版功能.

inspect.isasyncgenfunction(object)

如果该对象是一个 异步生成器 函数则返回 True,例如:

>>> async def agen():
...     yield 1
...
>>> inspect.isasyncgenfunction(agen)
True

3.6 新版功能.

在 3.8 版更改: 对于使用 functools.partial() 封装的函数,如果被封装的函数是一个 异步生成器 ,现在也会返回 True

inspect.isasyncgen(object)

如果该对象是一个由 异步生成器 函数创建的 异步生成器迭代器,则返回 True

3.6 新版功能.

inspect.istraceback(object)

如果该对象是一个回溯则返回 True

inspect.isframe(object)

如果该对象是一个帧对象则返回 True

inspect.iscode(object)

如果该对象是一个代码对象则返回 True

inspect.isbuiltin(object)

如果该对象是一个内置函数或一个绑定的内置方法,则返回 True

inspect.isroutine(object)

如果该对象是一个用户定义的或内置的函数或者方法,则返回 True

inspect.isabstract(object)

如果该对象是一个抽象基类则返回 True

inspect.ismethoddescriptor(object)

如果该对象是一个方法描述器,但 ismethod()isclass()isfunction()isbuiltin() 均不为真,则返回 True

例如,该函数对于 int.__add__ 为真。一个通过此测试的对象可以有 __get__() 方法,但不能有 __set__() 方法,除此以外的属性集合是可变的。一个 __name__ 属性通常是合理的,而 __doc__ 属性常常也是。

即使是通过描述器实现的函数,如果通过其他某一个测试,则 ismethoddescriptor() 测试则会返回 False。这单纯是因为其他测试提供了更多保证。比如,当一个对象通过 ismethod() 测试时,你可以使用 __func__ 等属性。

inspect.isdatadescriptor(object)

如果该对象是一个数据描述器则返回 True

数据描述器拥有 __set____delete__ 方法。比如属性(通过 Python 定义)、getset 和成员。后二者是通过 C 定义的,并且也有对应的更具体的测试,并且在不同的 Python 实现中也是健壮的。典型地,数据描述器会拥有 __name____doc__ 属性(属性、getset 和成员都包含这两个属性),但这并无保证。

inspect.isgetsetdescriptor(object)

如果该对象是一个 getset 描述器则返回 True

CPython implementation detail: getset 是在扩展模块中通过 PyGetSetDef 结构体定义的属性。对于不包含这种类型的 Python 实现,这个方法将永远返回 False

inspect.ismemberdescriptor(object)

如果该对象是一个成员描述器则返回 True

CPython implementation detail: 成员描述器是在扩展模块中通过 PyMemberDef 结构体定义的属性。对于不包含这种类型的 Python 实现,这个方法将永远返回 False

获取源代码

inspect.getdoc(object)

获取对象的文档字符串并通过 cleandoc() 进行清理。如果对象本身并未提供文档字符串并且这个对象是一个类、一个方法、一个属性或者一个描述器,将通过继承层级结构获取文档字符串。

在 3.5 版更改: 文档字符串没有被重写的话现在会被继承。

inspect.getcomments(object)

任意多行注释作为单一一个字符串返回。对于类、函数和方法,选取紧贴在该对象的源代码之前的注释;对于模块,选取 Python 源文件顶部的注释。如果对象的源代码不可获得,返回 None。这可能是因为对象是 C 语言中或者是在交互式命令行中定义的。

inspect.getfile(object)

返回定义了这个对象的文件名(包括文本文件或二进制文件)。如果该对象是一个内置模块、类或函数则会失败并引发一个 TypeError

inspect.getmodule(object)

尝试猜测该对象是在哪个模块中定义的。

inspect.getsourcefile(object)

返回定义了这个对象的 Python 源文件名。如果该对象是一个内置模块、类或函数则会失败并引发一个 TypeError

inspect.getsourcelines(object)

返回一个源代码行的列表和对象的起始行。实参可以是一个模块、类、方法、函数、回溯、帧或者代码对象。与该对象相关的源代码会按行构成一个列表,并且会有一个行号表示其中第一行代码出现在源文件的第几行。如果源代码不能被获取,则会引发一个 OSError

在 3.3 版更改: 现在会引发 OSError 而不是 IOError,后者现在是前者的一个别名。

inspect.getsource(object)

返回对象的源代码文本。实参可以是一个模块、类、方法、函数、回溯、帧或者代码对象。源代码会作为单一一个字符串被返回。如果源代码不能被获取,则会引发一个 OSError

在 3.3 版更改: 现在会引发 OSError 而不是 IOError,后者现在是前者的一个别名。

inspect.cleandoc(doc)

清理文档字符串中为对齐当前代码块进行的缩进

第一行的所有前缀空白符会被移除。从第二行开始所有可以被统一去除的空白符也会被去除。之后,首尾的空白行也会被移除。同时,所有制表符会被展开到空格。

使用 Signature 对象对可调用对象进行内省

3.3 新版功能.

Signature 对象代表了一个可调用对象的调用签名和返回值标注。要获取一个 Signature 对象,使用 signature() 函数。

inspect.signature(callable, *, follow_wrapped=True)

返回给定的 callable 的一个 Signature 对象:

>>> from inspect import signature
>>> def foo(a, *, b:int, **kwargs):
...     pass

>>> sig = signature(foo)

>>> str(sig)
'(a, *, b:int, **kwargs)'

>>> str(sig.parameters['b'])
'b:int'

>>> sig.parameters['b'].annotation
<class 'int'>

接受各类的 Python 可调用对象,包括单纯的函数、类,到 functools.partial() 对象。

如果无法提供签名,则会引发 ValueError,如果不支持该类型的对象,则会引发 TypeError

函数签名中的斜杠(/)表示在它之前的参数是仅限位置的。详见 编程常见问题中关于仅限位置参数的条目

3.5 新版功能: follow_wrapped 形参。传递 False 来获得特定关于 callable 的签名(callable.__wrapped__ 将不会用来解包被修饰的可调用对象)。

注解

一些可调用对象可能在特定 Python 实现中无法被内省。例如,在 CPython 中,部分通过 C 语言定义的内置函数不提供关于其参数的元数据。

class inspect.Signature(parameters=None, *, return_annotation=Signature.empty)

一个 Signature 对象代表了一个函数的调用签名和返回值标注。对于函数接受的每个参数,它对应地在自身的 parameters 容器中存储一个 Parameter 对象。

可选参数 parameters 是一个 Parameter 对象组成的序列,它会在之后被验证不存在名字重复的参数,并且参数处于正确的顺序,即仅限位置参数最前,之后紧接着可位置可关键字参数,并且有默认值参数在无默认值参数之前。

可选参数 return_annotation 可以是任意 Python 对象,是该可调用对象中“返回值”的标注。

 Signature 对象是 不可变 的。使用 Signature.replace() 来构造一个修改后的副本。

在 3.5 版更改:  Signature 对象既可封存又可哈希。

empty

该类的一个特殊标记来明确指出返回值标注缺失。

parameters

一个参数名字到对应 Parameter 对象的有序映射。参数以严格的定义顺序出现,包括仅关键字参数。

在 3.7 版更改: Python 从 3.7 版起才显式地保证了它保持仅关键字参数的定义顺序,尽管实践上在 Python 3 中一直保持了这个顺序。

return_annotation

可调用对象的“返回值”标注。如果可调用对象没有“返回值”标注,这个属性会被设置为 Signature.empty

bind(*args, **kwargs)

构造一个位置和关键字实参到形参的映射。如果 *args**kwargs 符合签名,则返回一个 BoundArguments;否则引发一个 TypeError

bind_partial(*args, **kwargs)

Signature.bind() 作用方式相同,但允许省略部分必要的参数(模仿 functools.partial() 的行为)。返回 BoundArguments,或者在传入参数不符合签名的情况下,引发一个 TypeError

replace(*[, parameters][, return_annotation])

基于 replace 函数被调用的目标,创建一个新的 Signature 实例。可以传递不同的 parameters 和/或 return_annotation 来覆盖原本签名的对应的属性。要从复制的 Signature 中移除 return_annotation,可以传入 Signature.empty

>>> def test(a, b):
...     pass
>>> sig = signature(test)
>>> new_sig = sig.replace(return_annotation="new return anno")
>>> str(new_sig)
"(a, b) -> 'new return anno'"
classmethod from_callable(obj, *, follow_wrapped=True)

Return a Signature (or its subclass) object for a given callable obj. Pass follow_wrapped=False to get a signature of obj without unwrapping its __wrapped__ chain.

该函数简化了创建 Signature 的子类的过程:

class MySignature(Signature):
    pass
sig = MySignature.from_callable(min)
assert isinstance(sig, MySignature)

3.5 新版功能.

class inspect.Parameter(name, kind, *, default=Parameter.empty, annotation=Parameter.empty)

 Parameter 对象是 不可变 的。不要直接修改 Parameter 对象,而是通过 Parameter.replace() 来创建一个修改后的副本。

在 3.5 版更改:  Parameter 对象既可封存(pickle)又可哈希。

empty

该类的一个特殊标记来明确指出默认值和标注的缺失。

name

参数的名字字符串。这个名字必须是一个合法的 Python 标识符。

CPython implementation detail: CPython 会为用于实现推导式和生成器表达式的代码对象构造形如 .0 的隐式形参名。

在 3.6 版更改: 这些形参名会被此模块暴露为形如 implicit0 一样的名字。

default

该参数的默认值。如果该参数没有默认值,这个属性会被设置为 Parameter.empty

annotation

该参数的标注。如果该参数没有标注,这个属性会被设置为 Parameter.empty

kind

描述实参值会如何绑定到形参。可能的取值(可以通过 Parameter 获得,比如 Parameter.KEYWORD_ONLY ):

名称

含意

POSITIONAL_ONLY

值必须以位置参数的方式提供。仅限位置参数是在函数定义中出现在 / 之前(如果有)的条目。

POSITIONAL_OR_KEYWORD

值既可以以关键字参数的形式提供,也可以以位置参数的形式提供(这是 Python 写成的函数的标准绑定行为的)。

VAR_POSITIONAL

没有绑定到其他形参的位置实参组成的元组。这对应于 Python 函数定义中的 *args 形参。

KEYWORD_ONLY

值必须以关键字参数的形式提供。仅限关键字形参是在 Python 函数定义中出现在 **args 之后的条目。

VAR_KEYWORD

一个未绑定到其他形参的关键字参数的字典。这对应于 Python 函数定义中的 **kwargs 形参。

例如,打印所有没有默认值的仅关键字参数:

>>> def foo(a, b, *, c, d=10):
...     pass

>>> sig = signature(foo)
>>> for param in sig.parameters.values():
...     if (param.kind == param.KEYWORD_ONLY and
...                        param.default is param.empty):
...         print('Parameter:', param)
Parameter: c
kind.description

描述 Parameter.kind 的枚举值。

3.8 新版功能.

例子:打印所有参数的描述:

>>> def foo(a, b, *, c, d=10):
...     pass

>>> sig = signature(foo)
>>> for param in sig.parameters.values():
...     print(param.kind.description)
positional or keyword
positional or keyword
keyword-only
keyword-only
replace(*[, name][, kind][, default][, annotation])

基于 replace 函数被调用的目标,创建一个新的 Parameter 实例。要覆写 Parameter 的属性,传递对应的参数。要移除 Parameter 的默认值和/或标注,传递 Parameter.empty

>>> from inspect import Parameter
>>> param = Parameter('foo', Parameter.KEYWORD_ONLY, default=42)
>>> str(param)
'foo=42'

>>> str(param.replace()) # Will create a shallow copy of 'param'
'foo=42'

>>> str(param.replace(default=Parameter.empty, annotation='spam'))
"foo:'spam'"

在 3.4 版更改: 在 Python 3.3 中, Parameter 对象当 kindPOSITIONAL_ONLY 时允许 name 被设置为 None。这现在已不再被允许。

class inspect.BoundArguments

调用 Signature.bind()Signature.bind_partial() 的结果。容纳实参到函数的形参的映射。

arguments

一个形参名到实参值的可变映射。仅包含显式绑定的参数。对 arguments 的修改会反映到 argskwargs 上。

应当在任何参数处理目的中与 Signature.parameters 结合使用。

注解

 Signature.bind()Signature.bind_partial() 中采用默认值的参数被跳过。然而,如果有需要的话,可以使用 BoundArguments.apply_defaults() 来添加它们。

在 3.9 版更改:  arguments 现在的类型是 dict。之前,它的类型是 collections.OrderedDict

args

位置参数的值的元组。由 arguments 属性动态计算。

kwargs

关键字参数值的字典。由 arguments 属性动态计算。

signature

向所属 Signature 对象的一个引用。

apply_defaults()

设置缺失的参数的默认值。

对于变长位置参数(*args),默认值是一个空元组。

对于变长关键字参数(**kwargs)默认值是一个空字典。

>>> def foo(a, b='ham', *args): pass
>>> ba = inspect.signature(foo).bind('spam')
>>> ba.apply_defaults()
>>> ba.arguments
{'a': 'spam', 'b': 'ham', 'args': ()}

3.5 新版功能.

 argskwargs 属性可以被用于调用函数:

def test(a, *, b):
    ...

sig = signature(test)
ba = sig.bind(10, b=20)
test(*ba.args, **ba.kwargs)

参见

PEP 362 - 函数签名对象。

包含具体的规范,实现细节和样例。

类与函数

inspect.getclasstree(classes, unique=False)

将给定的类的列表组织成嵌套列表的层级结构。每当一个内层列表出现时,它包含的类均派生自紧接着该列表之前的条目的类。每个条目均是一个二元组,包含一个类和它的基类组成的元组。如果 unique 参数为真值,则给定列表中的每个类将恰有一个对应条目。否则,运用了多重继承的类和它们的后代将出现多次。

inspect.getargspec(func)

获取一个 Python 函数的形参的名字和默认值。将返回一个 具名元组 ArgSpec(args, varargs, keywords, defaults)args 是一个形参名字的列表。 varargskeywords*** 形参的名字或 Nonedefaults 是一个默认参数值的元组或没有默认值时取 None。如果该元组有 n 个元素,则它们对应 args 中的最后 n 个元素。

3.0 版后已移除: 通常可以替换为使用更新后的 API getfullargspec(),后者还能正确处理函数标注和仅限关键字形参。

又或者,使用 signature()Signature 对象,这提供一个更加结构化的处理可调用对象的内省 API。

inspect.getfullargspec(func)

获取一个 Python 函数的形参的名字和默认值。将返回一个 具名元组

FullArgSpec(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)

args 是一个位置参数的名字的列表。 varargs* 形参的名字或 None 表示不接受任意长位置参数时。 varkw** 参数的名字,或 None 表示不接受任意关键字参数。 defaults 是一个包含了默认参数值的 n 元组分别对应最后 n 个位置参数,或 None 则表示没有默认值。 kwonlyargs 是一个仅关键词参数列表,保持定义时的顺序。 kwonlydefaults 是一个字典映射自 kwonlyargs 中包含的形参名。 annotations 是一个字典,包含形参值到标注的映射。其中包含一个特殊的键 "return" 代表函数返回值的标注(如果有的话)。

注意: signature()Signature 对象 提供可调用对象内省更推荐的 API,并且支持扩展模块 API 中可能出现的额外的行为(比如仅限位置参数)。该函数被保留的主要原因是保持兼容 Python 2 的 inspect 模块 API。

在 3.4 版更改: 该函数现在基于 signature() 但仍然忽略 __wrapped__ 属性,并且在签名中包含绑定方法中的第一个绑定参数。

在 3.6 版更改: 该方法在 Python 3.5 中曾因 signature() 被文档归为弃用。但该决定已被推翻以恢复一个明确受支持的标准接口,以便运用一份源码通用 Python 2/3 间遗留的 getargspec() API 的迁移。

在 3.7 版更改: Python 从 3.7 版起才显式地保证了它保持仅关键字参数的定义顺序,尽管实践上在 Python 3 中一直保持了这个顺序。

inspect.getargvalues(frame)

获取传入特定的帧的实参的信息。将返回一个 具名元组 ArgInfo(args, varargs, keywords, locals)args 是一个参数名字的列表。 varargskeyword*** 参数的名字或 Nonelocals 是给定的帧的局部环境字典。

注解

该函数因疏忽在 Python 3.5 中被错误地标记为弃用。

inspect.formatargspec(args[, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations[, formatarg, formatvarargs, formatvarkw, formatvalue, formatreturns, formatannotations]])

getfullargspec() 的返回值格式化为美观的参数规格。

最初的七个参数是 (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations) 。

其他6个参数分别是会被调用以转化参数名、* 参数名、** 参数名、默认值、返回标注和独立标注为字符串的函数。

例如:

>>> from inspect import formatargspec, getfullargspec
>>> def f(a: int, b: float):
...     pass
...
>>> formatargspec(*getfullargspec(f))
'(a: int, b: float)'

3.5 版后已移除: 使用 signature()Signature 对象,它为可调用对象提供一个更好的内省 API。

inspect.formatargvalues(args[, varargs, varkw, locals, formatarg, formatvarargs, formatvarkw, formatvalue])

getargvalues() 返回的四个值格式化为美观的参数规格。 format* 的参数是对应的可选格式化函数以转化名字和值为字符串。

注解

该函数因疏忽在 Python 3.5 中被错误地标记为弃用。

inspect.getmro(cls)

返回由类 cls 的全部基类按方法解析顺序组成的元组,包括 cls 本身。所有类不会在此元组中出现多于一次。注意方法解析顺序取决于 cls 的类型。除非使用一个非常奇怪的用户定义元类型,否则 cls 会是元组的第一个元素。

inspect.getcallargs(func, /, *args, **kwds)

仿照调用方式绑定 argskwds 到 Python 函数或方法 func 参数名。对于绑定方法,也绑定第一个参数(通常命名为 self)到关联的实例。返回一个字典,映射自参数名(包括可能存在的 *** 参数)到他们对应于 argskwds 中的值。假使 func 被错误地调用,即是说 func(*args, **kwds) 会因函数签名不一致引发一个异常,那么也会引发一个相同种类的异常,并附上相同或类似的消息。例如:

>>> from inspect import getcallargs
>>> def f(a, b=1, *pos, **named):
...     pass
>>> getcallargs(f, 1, 2, 3) == {'a': 1, 'named': {}, 'b': 2, 'pos': (3,)}
True
>>> getcallargs(f, a=2, x=4) == {'a': 2, 'named': {'x': 4}, 'b': 1, 'pos': ()}
True
>>> getcallargs(f)
Traceback (most recent call last):
...
TypeError: f() missing 1 required positional argument: 'a'

3.2 新版功能.

3.5 版后已移除: 改使用 Signature.bind()Signature.bind_partial()

inspect.getclosurevars(func)

获取自 Python 函数或方法 func 引用的外部名字到它们的值的映射。返回一个 具名元组 ClosureVars(nonlocals, globals, builtins, unbound)nonlocals 映射引用的名字到词法闭包变量,globals 映射到函数的模块级全局, builtins 映射到函数体内可见的内置变量。 unbound 是在函数中引用但不能解析到给定的模块全局和内置变量的名字的集合。

如果 func 不是 Python 函数或方法,将引发 TypeError

3.3 新版功能.

inspect.unwrap(func, *, stop=None)

获取 func 所包装的对象。它追踪 __wrapped__ 属性链并返回最后一个对象。

stop 是一个可选的回调,接受包装链的一个对象作为唯一参数,以允许通过让回调返回真值使解包装更早中止。如果回调不曾返回一个真值,将如常返回链中的最后一个对象。例如, signature() 使用该参数来在遇到具有 __signature__ 参数的对象时停止解包装。

如果遇到循环,则引发 ValueError

3.4 新版功能.

解释器栈

当下列函数返回“帧记录”时,每个记录是一个 具名元组 FrameInfo(frame, filename, lineno, function, code_context, index)。该元组包含帧对象、文件名、当前行的行号、函数名、来源于源代码的若干行上下文组成的列表和当前行在该列表中的索引。

在 3.5 版更改: 不再返回一个元组而是返回一个具名元组。

注解

保留帧对象的引用(可见于这些函数返回的帧记录的第一个元素)会导致你的程序产生循环引用。每当一个循环引用被创建,所有可从产生循环的对象访问的对象的生命周期将会被大幅度延长,即便 Python 的可选的循环检测器被启用。如果这类循环必须被创建,确保它们会被显式地打破以避免对象销毁被延迟从而导致占用内存增加。

尽管循环检测器能够处理这种情况,这些帧(包括其局部变量)的销毁可以通过在 finally 子句中移除循环来产生确定的行为。对于循环检测器在编译 Python 时被禁用或者使用 gc.disable() 时,这样处理更加尤为重要。比如:

def handle_stackframe_without_leak():
    frame = inspect.currentframe()
    try:
        # do something with the frame
    finally:
        del frame

如果你希望保持帧更长的时间(比如在之后打印回溯),你也可以通过 frame.clear() 方法打破循环引用。

大部分这些函数支持的可选的 context 参数指定返回时包含的上下文的行数,以当前行为中心。

inspect.getframeinfo(frame, context=1)

获取一个帧或者一个回溯对象的信息。返回一个 具名元组 Traceback(filename, lineno, function, code_context, index)

inspect.getouterframes(frame, context=1)

获取某帧及其所有外部帧的帧记录的列表。这些帧表示了导致 frame 被创建的一系列调用。返回的列表中的第一个记录代表了 frame 本身;最后一个记录代表了 frame 的栈上的最外层的调用。

在 3.5 版更改: 返回一个 具名元组 FrameInfo(frame, filename, lineno, function, code_context, index) 的列表。

inspect.getinnerframes(traceback, context=1)

获取一个回溯所在的帧和它所有的内部的帧的列表。这些帧代表了作为 frame 的后续的帧。第一条记录代表了 traceback 本身;最后一条记录代表了引发异常的位置。

在 3.5 版更改: 返回一个 具名元组 FrameInfo(frame, filename, lineno, function, code_context, index) 的列表。

inspect.currentframe()

返回调用者的栈帧对应的帧对象。

CPython implementation detail: 该函数依赖于 Python 解释器对于栈帧的支持,这并非在 Python 的所有实现中被保证。该函数在不支持Python 栈帧的实现中运行会返回 None

inspect.stack(context=1)

返回调用者的栈的帧记录列表。第一个记录代表调用者,最后一个记录代表了栈上最外层的调用。

在 3.5 版更改: 返回一个 具名元组 FrameInfo(frame, filename, lineno, function, code_context, index) 的列表。

inspect.trace(context=1)

返回介于当前帧和引发了当前正在处理的异常的帧之间的所有帧记录的列表。列表中的第一条记录代表调用者;最后一条记录代表了引发异常的地方。

在 3.5 版更改: 返回一个 具名元组 FrameInfo(frame, filename, lineno, function, code_context, index) 的列表。

静态地获取属性

 getattr()hasattr() 都可能会在获取或者判断属性是否存在时触发代码执行。描述符,就和特性一样,会被调用, __getattr__()__getattribute__() 可能会被调用。

对于你想要静态地内省的情况,比如文档工具,这会显得不方便。 getattr_static() 拥有与 getattr() 相同的签名,但避免了获取属性时执行代码。

inspect.getattr_static(obj, attr, default=None)

获取属性而不触发描述器协议的动态查找能力 __getattr__()__getattribute__()

注意:该函数可能无法获取 getattr 能获取的全部的属性(比如动态地创建的属性),并且可能发现一些 getattr 无法找到的属性(比如描述器会引发 AttributeError)。它也能够返回描述器对象本身而非实例成员。

如果实例的 __dict__ 被其他成员遮盖(比如一个特性)则该函数无法找到实例成员。

3.2 新版功能.

 getattr_static() 不解析描述器。比如槽描述器或 C 语言中实现的 getset 描述器。该描述器对象会被直接返回,而不处理底层属性。

你可以用类似下方的代码的方法处理此事。注意,对于任意 getset 描述符,使用这段代码仍可能触发代码执行。

# example code for resolving the builtin descriptor types
class _foo:
    __slots__ = ['foo']

slot_descriptor = type(_foo.foo)
getset_descriptor = type(type(open(__file__)).name)
wrapper_descriptor = type(str.__dict__['__add__'])
descriptor_types = (slot_descriptor, getset_descriptor, wrapper_descriptor)

result = getattr_static(some_object, 'foo')
if type(result) in descriptor_types:
    try:
        result = result.__get__()
    except AttributeError:
        # descriptors can raise AttributeError to
        # indicate there is no underlying value
        # in which case the descriptor itself will
        # have to do
        pass

生成器和协程的当前状态

当实现协程调度器或其他更高级的生成器用途时,判断一个生成器是正在执行、等待启动或继续或执行,又或者已经被终止是非常有用的。 getgeneratorstate() 允许方便地判断一个生成器的当前状态。

inspect.getgeneratorstate(generator)

获取生成器迭代器的当前状态。

可能的状态是:
  • GEN_CREATED:等待开始执行。

  • GEN_RUNNING:正在被解释器执行。

  • GEN_SUSPENDED:当前挂起于一个 yield 表达式。

  • GEN_CLOSED:执行已经完成。

3.2 新版功能.

inspect.getcoroutinestate(coroutine)

获取协程对象的当前状态。该函数设计为用于使用 async def 函数创建的协程函数,但也能接受任何包括 cr_runningcr_frame 的类似协程的对象。

可能的状态是:
  • CORO_CREATED:等待开始执行。

  • CORO_RUNNING:当前正在被解释器执行。

  • CORO_SUSPENDED:当前挂起于一个 await 表达式。

  • CORO_CLOSED:执行已经完成。

3.5 新版功能.

生成器当前的内部状态也可以被查询。这通常在测试目的中最为有用,来保证内部状态如预期一样被更新:

inspect.getgeneratorlocals(generator)

获取 generator 里的实时局部变量到当前值的映射。返回一个由名字映射到值的字典。这与在生成器的主体内调用 locals() 是等效的,并且相同的警告也适用。

如果 generator 是一个没有关联帧的 生成器,则返回一个空字典。如果 generator 不是一个 Python 生成器对象,则引发 TypeError

CPython implementation detail: 该函数依赖于生成器为内省暴露一个 Python 栈帧,这并非在 Python 的所有实现中被保证。在这种情况下,该函数将永远返回一个空字典。

3.3 新版功能.

inspect.getcoroutinelocals(coroutine)

该函数可类比于 getgeneratorlocals(),只是作用于由 async def 函数创建的协程。

3.5 新版功能.

代码对象位标志

Python 代码对象有一个 co_flags 属性,它是下列标志的位图。

inspect.CO_OPTIMIZED

代码对象已经经过优化,会采用快速局部变量。

inspect.CO_NEWLOCALS

如果被置位,当代码对象被执行时会创建一个新的字典作为帧的 f_locals

inspect.CO_VARARGS

代码对象拥有一个变长位置形参(类似 *args)。

inspect.CO_VARKEYWORDS

代码对象拥有一个可变关键字形参 (类似 **kwrags)。

inspect.CO_NESTED

该标志当代码对象是一个嵌套函数时被置位。

inspect.CO_GENERATOR

当代码对象是一个生成器函数,即调用时会返回一个生成器对象,则该标志被置位。

inspect.CO_NOFREE

当没有自由或单元变量时,标志被置位。

inspect.CO_COROUTINE

当代码对象是一个协程函数时被置位。当代码对象被执行时它返回一个协程。详见 PEP 492

3.5 新版功能.

inspect.CO_ITERABLE_COROUTINE

该标志被用于将生成器转变为基于生成器的协程。包含此标志的生成器对象可以被用于 await 表达式,并可以 yield from 协程对象。详见 PEP 492

3.5 新版功能.

inspect.CO_ASYNC_GENERATOR

当代码对象是一个异步生成器函数时该标志被置位。当代码对象被运行时它将返回一个异步生成器对象。详见 PEP 525

3.6 新版功能.

注解

这些标志特指于 CPython,并且在其他 Python 实现中可能从未被定义。更进一步地说,这些标志是一种实现细节,并且可能在将来的 Python 发行中被移除或弃用。推荐使用 inspect 模块的公共 API 来进行任何内省需求。

命令行界面

inspect 模块也提供一个从命令行使用基本的内省能力。

默认地,命令行接受一个模块的名字并打印模块的源代码。也可通过后缀一个冒号和目标对象的限定名称来打印一个类或者一个函数。

--details

打印特定对象的信息而非源码。