inspect模块
类型和成员
inspect.getmembers(object[, predicate]): 返回一个对象的所有成员,返回形式是一个列表,列表中每个元素是一个二元组,分别为成员名称及成员内容。
下面以一个函数为例,演示一下都有哪些成员。 注意,__builtins__
和__globals__
两个特殊属性里有非常多与函数本身无关的内容,占用行数太多,所以没有打印。
import inspect
def add(a: int=10, b:int=20, *, c=30):
'''这是一个函数'''
return a+b+c
ret = inspect.getmembers(add)
print(type(ret))
print(len(ret))
print('-' * 25, '分隔线', '-' * 25)
for item in ret:
if item[0] in ('__builtins__', '__globals__'):
continue
print(item)
print('-' * 25, '分隔线', '-' * 25)
print(len(dir(add)))
for item in dir(add):
print(item)
print('-' * 25, '分隔线', '-' * 25)
print(f'{vars(add) = }')
print('-' * 25, '分隔线', '-' * 25)
print(f'{add.__annotations__ = }')
print(f'{add.__defaults__ = }')
输出结果:
<class 'list'>
37
------------------------- 分隔线 -------------------------
('__annotations__', {'a': <class 'int'>, 'b': <class 'int'>})
('__call__', <method-wrapper '__call__' of function object at 0x000001F66FAA04A0>)
('__class__', <class 'function'>)
('__closure__', None)
('__code__', <code object add at 0x000001F66FAF9140, file "F:\RolandWork\PythonProjects\studyPython\forTest.py", line 3>)
('__defaults__', (10, 20))
('__delattr__', <method-wrapper '__delattr__' of function object at 0x000001F66FAA04A0>)
('__dict__', {})
('__dir__', <built-in method __dir__ of function object at 0x000001F66FAA04A0>)
('__doc__', '这是一个函数')
('__eq__', <method-wrapper '__eq__' of function object at 0x000001F66FAA04A0>)
('__format__', <built-in method __format__ of function object at 0x000001F66FAA04A0>)
('__ge__', <method-wrapper '__ge__' of function object at 0x000001F66FAA04A0>)
('__get__', <method-wrapper '__get__' of function object at 0x000001F66FAA04A0>)
('__getattribute__', <method-wrapper '__getattribute__' of function object at 0x000001F66FAA04A0>)
('__getstate__', <built-in method __getstate__ of function object at 0x000001F66FAA04A0>)
('__gt__', <method-wrapper '__gt__' of function object at 0x000001F66FAA04A0>)
('__hash__', <method-wrapper '__hash__' of function object at 0x000001F66FAA04A0>)
('__init__', <method-wrapper '__init__' of function object at 0x000001F66FAA04A0>)
('__init_subclass__', <built-in method __init_subclass__ of type object at 0x00007FF8EDA44290>)
('__kwdefaults__', {'c': 30})
('__le__', <method-wrapper '__le__' of function object at 0x000001F66FAA04A0>)
('__lt__', <method-wrapper '__lt__' of function object at 0x000001F66FAA04A0>)
('__module__', '__main__')
('__name__', 'add')
('__ne__', <method-wrapper '__ne__' of function object at 0x000001F66FAA04A0>)
('__new__', <built-in method __new__ of type object at 0x00007FF8EDA44290>)
('__qualname__', 'add')
('__reduce__', <built-in method __reduce__ of function object at 0x000001F66FAA04A0>)
('__reduce_ex__', <built-in method __reduce_ex__ of function object at 0x000001F66FAA04A0>)
('__repr__', <method-wrapper '__repr__' of function object at 0x000001F66FAA04A0>)
('__setattr__', <method-wrapper '__setattr__' of function object at 0x000001F66FAA04A0>)
('__sizeof__', <built-in method __sizeof__ of function object at 0x000001F66FAA04A0>)
('__str__', <method-wrapper '__str__' of function object at 0x000001F66FAA04A0>)
('__subclasshook__', <built-in method __subclasshook__ of type object at 0x00007FF8EDA44290>)
------------------------- 分隔线 -------------------------
37
__annotations__
__builtins__
__call__
__class__
__closure__
__code__
__defaults__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__get__
__getattribute__
__getstate__
__globals__
__gt__
__hash__
__init__
__init_subclass__
__kwdefaults__
__le__
__lt__
__module__
__name__
__ne__
__new__
__qualname__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
------------------------- 分隔线 -------------------------
vars(add) = {}
------------------------- 分隔线 -------------------------
add.__annotations__ = {'a': <class 'int'>, 'b': <class 'int'>}
add.__defaults__ = (10, 20)
可以看出,函数返回的成员与使用dir函数返回的成员数量相同。
下面看一下一个类的成员
import inspect
class Foo:
'''这是一个类'''
prop1 = 123
def m1(self):
print('m1 method')
ret = inspect.getmembers(Foo)
print(type(ret))
print(len(ret))
print('-' * 25, '分隔线', '-' * 25)
for item in ret:
print(item)
print('-' * 25, '分隔线', '-' * 25)
print(len(dir(Foo)))
for item in dir(Foo):
print(item)
print('-' * 25, '分隔线', '-' * 25)
print(f'{vars(Foo) = }')
输出结果:
<class 'list'>
29
------------------------- 分隔线 -------------------------
('__class__', <class 'type'>)
('__delattr__', <slot wrapper '__delattr__' of 'object' objects>)
('__dict__', mappingproxy({'__module__': '__main__', '__doc__': '这是一个类', 'prop1': 123, 'm1': <function Foo.m1 at 0x0000024513D139C0>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>}))
('__dir__', <method '__dir__' of 'object' objects>)
('__doc__', '这是一个类')
('__eq__', <slot wrapper '__eq__' of 'object' objects>)
('__format__', <method '__format__' of 'object' objects>)
('__ge__', <slot wrapper '__ge__' of 'object' objects>)
('__getattribute__', <slot wrapper '__getattribute__' of 'object' objects>)
('__getstate__', <method '__getstate__' of 'object' objects>)
('__gt__', <slot wrapper '__gt__' of 'object' objects>)
('__hash__', <slot wrapper '__hash__' of 'object' objects>)
('__init__', <slot wrapper '__init__' of 'object' objects>)
('__init_subclass__', <built-in method __init_subclass__ of type object at 0x000002451395AB80>)
('__le__', <slot wrapper '__le__' of 'object' objects>)
('__lt__', <slot wrapper '__lt__' of 'object' objects>)
('__module__', '__main__')
('__ne__', <slot wrapper '__ne__' of 'object' objects>)
('__new__', <built-in method __new__ of type object at 0x00007FF8BE5F8DF0>)
('__reduce__', <method '__reduce__' of 'object' objects>)
('__reduce_ex__', <method '__reduce_ex__' of 'object' objects>)
('__repr__', <slot wrapper '__repr__' of 'object' objects>)
('__setattr__', <slot wrapper '__setattr__' of 'object' objects>)
('__sizeof__', <method '__sizeof__' of 'object' objects>)
('__str__', <slot wrapper '__str__' of 'object' objects>)
('__subclasshook__', <built-in method __subclasshook__ of type object at 0x000002451395AB80>)
('__weakref__', <attribute '__weakref__' of 'Foo' objects>)
('m1', <function Foo.m1 at 0x0000024513D139C0>)
('prop1', 123)
------------------------- 分隔线 -------------------------
29
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__getstate__
__gt__
__hash__
__init__
__init_subclass__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
m1
prop1
------------------------- 分隔线 -------------------------
vars(Foo) = mappingproxy({'__module__': '__main__', '__doc__': '这是一个类', 'prop1': 123, 'm1': <function Foo.m1 at 0x0000024513D139C0>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>})
下面是Foo类的实例的成员
import inspect
class Foo:
'''这是一个类'''
prop1 = 123
def m1(self):
print('m1 method')
foo = Foo()
foo.foo_prop = '这是实例的属性'
ret = inspect.getmembers(foo)
print(type(ret))
print(len(ret))
print('-' * 25, '分隔线', '-' * 25)
for item in ret:
print(item)
print('-' * 25, '分隔线', '-' * 25)
print(len(dir(foo)))
for item in dir(foo):
print(item)
print('-' * 25, '分隔线', '-' * 25)
print(f'{vars(foo) = }')
输出结果:
<class 'list'>
30
------------------------- 分隔线 -------------------------
('__class__', <class '__main__.Foo'>)
('__delattr__', <method-wrapper '__delattr__' of Foo object at 0x0000022CD81856D0>)
('__dict__', {'foo_prop': '这是实例的属性'})
('__dir__', <built-in method __dir__ of Foo object at 0x0000022CD81856D0>)
('__doc__', '这是一个类')
('__eq__', <method-wrapper '__eq__' of Foo object at 0x0000022CD81856D0>)
('__format__', <built-in method __format__ of Foo object at 0x0000022CD81856D0>)
('__ge__', <method-wrapper '__ge__' of Foo object at 0x0000022CD81856D0>)
('__getattribute__', <method-wrapper '__getattribute__' of Foo object at 0x0000022CD81856D0>)
('__getstate__', <built-in method __getstate__ of Foo object at 0x0000022CD81856D0>)
('__gt__', <method-wrapper '__gt__' of Foo object at 0x0000022CD81856D0>)
('__hash__', <method-wrapper '__hash__' of Foo object at 0x0000022CD81856D0>)
('__init__', <method-wrapper '__init__' of Foo object at 0x0000022CD81856D0>)
('__init_subclass__', <built-in method __init_subclass__ of type object at 0x0000022CD7EFF9D0>)
('__le__', <method-wrapper '__le__' of Foo object at 0x0000022CD81856D0>)
('__lt__', <method-wrapper '__lt__' of Foo object at 0x0000022CD81856D0>)
('__module__', '__main__')
('__ne__', <method-wrapper '__ne__' of Foo object at 0x0000022CD81856D0>)
('__new__', <built-in method __new__ of type object at 0x00007FF8BCBD8DF0>)
('__reduce__', <built-in method __reduce__ of Foo object at 0x0000022CD81856D0>)
('__reduce_ex__', <built-in method __reduce_ex__ of Foo object at 0x0000022CD81856D0>)
('__repr__', <method-wrapper '__repr__' of Foo object at 0x0000022CD81856D0>)
('__setattr__', <method-wrapper '__setattr__' of Foo object at 0x0000022CD81856D0>)
('__sizeof__', <built-in method __sizeof__ of Foo object at 0x0000022CD81856D0>)
('__str__', <method-wrapper '__str__' of Foo object at 0x0000022CD81856D0>)
('__subclasshook__', <built-in method __subclasshook__ of type object at 0x0000022CD7EFF9D0>)
('__weakref__', None)
('foo_prop', '这是实例的属性')
('m1', <bound method Foo.m1 of <__main__.Foo object at 0x0000022CD81856D0>>)
('prop1', 123)
------------------------- 分隔线 -------------------------
30
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__getstate__
__gt__
__hash__
__init__
__init_subclass__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
foo_prop
m1
prop1
------------------------- 分隔线 -------------------------
vars(foo) = {'foo_prop': '这是实例的属性'}
此函数第二个参数predicate需要传递一个函数,该函数作用于getmembers函数返回的列表中的对象,用于过滤。一般传递本模块中is开头的函数(比如isfunction, ismethod)。
import inspect
class Foo:
'''这是一个类'''
prop1 = 123
def m1(self):
print('m1 method')
def __str__(self):
print('这是Foo类')
foo = Foo()
foo.foo_prop = '这是实例的属性'
print('-' * 25, '分隔线', '-' * 25)
print(inspect.isfunction(Foo.m1))
print(inspect.isfunction(foo.m1))
print(inspect.ismethod(Foo.m1))
print(inspect.ismethod(foo.m1))
print('-' * 25, '分隔线', '-' * 25)
ret = inspect.getmembers(Foo, inspect.isfunction)
print(ret)
print('-' * 25, '分隔线', '-' * 25)
ret = inspect.getmembers(Foo, inspect.ismethod)
print(ret)
print('-' * 25, '分隔线', '-' * 25)
ret = inspect.getmembers(foo, inspect.isfunction)
print(ret)
print('-' * 25, '分隔线', '-' * 25)
ret = inspect.getmembers(foo, inspect.ismethod)
print(ret)
输出结果:
------------------------- 分隔线 -------------------------
True
False
False
True
------------------------- 分隔线 -------------------------
[('__str__', <function Foo.__str__ at 0x0000017792764180>), ('m1', <function Foo.m1 at 0x00000177925039C0>)]
------------------------- 分隔线 -------------------------
[]
------------------------- 分隔线 -------------------------
[]
------------------------- 分隔线 -------------------------
[('__str__', <bound method Foo.__str__ of <__main__.Foo object at 0x0000017792505A50>>), ('m1', <bound method Foo.m1 of <__main__.Foo object at 0x0000017792505A50>>)]
从输出结果中可以看到,类中定义的函数其实可以看做是一个普通函数。当类实例化为对象后,对象就绑定了类中的函数,成为了实例方法。自定义中继承的特殊方法不会列出,除非重写了某个特殊方法,比如示例中的__str__
方法。
下面是一些判断对象类型的函数。比如,isfunction, ismethod, isclass, isgenerator等等。
import inspect
def f_func():
'''这是一个函数'''
pass
def f_generator():
'''这是一个生成器函数'''
yield 1
yield 2
yield 3
class GetDescriptor:
'''这是一个非数据描述器'''
def __get__(self, instance, owner):
return(instance, owner)
class DataDescriptor:
'''这是一个数据描述器'''
def __set__(self, instance, value):
print(instance, value)
def __get__(self, instance, owner):
print(instance, owner)
class Foo:
'''这是一个类'''
prop1 = 123
prop_get_desc = GetDescriptor()
prop_data_desc = DataDescriptor()
def m1(self):
print('m1 method')
foo = Foo()
gen = f_generator()
print(inspect.isfunction(f_func)) # True f_func是全局函数
print(inspect.ismethod(f_func)) # False f_func是全局函数
print(inspect.isfunction(Foo.m1)) # True Foo.m1是类中定义的函数
print(inspect.ismethod(Foo.m1)) # False Foo.m1是类中定义的函数
print(inspect.isfunction(foo.m1)) # False foo.m1是绑定到实例的方法
print(inspect.ismethod(foo.m1)) # True foo.m1是绑定到实例的方法
print('-' * 25, '分隔线', '-' * 25)
print(inspect.isclass(Foo)) # True
print(inspect.isgeneratorfunction(f_generator)) # True f_generator是生成器函数
print(inspect.isgenerator(f_generator)) # False f_generator是生成器函数
print(inspect.isgeneratorfunction(gen)) # False # gen是生成器
print(inspect.isgenerator(gen)) # True # gen是生成器
print('-' * 25, '分隔线', '-' * 25)
print(inspect.isdatadescriptor(GetDescriptor())) # False
print(inspect.isdatadescriptor(Foo.__dict__['prop_get_desc'])) # False
print(inspect.isdatadescriptor(DataDescriptor())) # True
print(inspect.isdatadescriptor(Foo.__dict__['prop_data_desc'])) # True
注意,ismethoddescriptor用法我没搞懂。 isdatadescriptor用来检测是否为数据描述器,而我没找到非数据描述器的检测函数。另外,isgetsetdescriptor和ismemberdescriptor是C语言底层实现时用到的,我们不能直接拿来用,通常也用不对。
获取源代码
下面是一些获取源代码的函数示例:
import inspect
def fn():
'''这是一个函数'''
pass
print('-' * 25, '分隔线', '-' * 25)
print(inspect.getdoc(fn))
print('-' * 25, '分隔线', '-' * 25)
print(inspect.getfile(fn))
print('-' * 25, '分隔线', '-' * 25)
print(inspect.getmodule(fn))
print('-' * 25, '分隔线', '-' * 25)
print(inspect.getsourcefile(fn))
print('-' * 25, '分隔线', '-' * 25)
print(inspect.getsourcelines(fn))
print('-' * 25, '分隔线', '-' * 25)
print(inspect.getsource(fn))
print('-' * 25, '分隔线', '-' * 25)
输出结果:
------------------------- 分隔线 -------------------------
这是一个函数
------------------------- 分隔线 -------------------------
F:\RolandWork\PythonProjects\studyPython\forTest.py
------------------------- 分隔线 -------------------------
<module '__main__' from 'F:\\RolandWork\\PythonProjects\\studyPython\\forTest.py'>
------------------------- 分隔线 -------------------------
F:\RolandWork\PythonProjects\studyPython\forTest.py
------------------------- 分隔线 -------------------------
(['def fn():\n', " '''这是一个函数'''\n", ' pass\n'], 3)
------------------------- 分隔线 -------------------------
def fn():
'''这是一个函数'''
pass
------------------------- 分隔线 -------------------------
callable对象签名
inspect.signature(callable, *, follow_wrapped=True, globals=None, locals=None, eval_str=False)
: 查看函数签名,返回一个Signature对象。对象中parameters属性里包含的是由Parameter对象组成的字典。
import inspect
def foo(a, /, b, *, c, d: int=10, **kwargs) -> int:
print(a,b,c,d,kwargs)
sig = inspect.signature(foo)
print('-' * 25, '分隔线', '-' * 25)
print(sig)
print(sig.parameters)
print(sig.parameters.values())
print('-' * 25, '分隔线', '-' * 25)
for k, v in sig.parameters.items():
print(k, v.kind, v.annotation, v.default)
print('-' * 25, '分隔线', '-' * 25)
print(sig.return_annotation)
输出结果:
------------------------- 分隔线 -------------------------
(a, /, b, *, c, d: int = 10, **kwargs) -> int
OrderedDict([('a', <Parameter "a">), ('b', <Parameter "b">), ('c', <Parameter "c">), ('d', <Parameter "d: int = 10">), ('kwargs', <Parameter "**kwargs">)])
odict_values([<Parameter "a">, <Parameter "b">, <Parameter "c">, <Parameter "d: int = 10">, <Parameter "**kwargs">])
------------------------- 分隔线 -------------------------
a POSITIONAL_ONLY <class 'inspect._empty'> <class 'inspect._empty'>
b POSITIONAL_OR_KEYWORD <class 'inspect._empty'> <class 'inspect._empty'>
c KEYWORD_ONLY <class 'inspect._empty'> <class 'inspect._empty'>
d KEYWORD_ONLY <class 'int'> 10
kwargs VAR_KEYWORD <class 'inspect._empty'> <class 'inspect._empty'>
------------------------- 分隔线 -------------------------
<class 'int'>
上面示例中使用获取的Signature对象我们可以查看参数类型提示,缺省值,位置还是关键字参数等等信息。
Signature.bind(*args, **kwargs)
: 将函数参数绑定实参,返回一个BoundArguments对象。
import inspect
def foo(a, /, b, *, c, d: int=10, **kwargs) -> int:
print(a,b,c,d,kwargs)
sig = inspect.signature(foo)
print('-' * 25, '分隔线', '-' * 25)
ag = sig.bind(1, 2, c=3) # 必须将所有没有缺省值的参数都绑定,否则会报错。 比如sig.bind(1,2)就会报错
print(ag.signature)
print(ag)
print(ag.arguments)
print(ag.args)
print(ag.kwargs)
ag.apply_defaults()
print('-' * 25, '分隔线', '-' * 25)
print(ag)
print(ag.arguments)
print(ag.args)
print(ag.kwargs)
print('-' * 25, '分隔线', '-' * 25)
foo(*ag.args, **ag.kwargs)
输出结果:
------------------------- 分隔线 -------------------------
(a, /, b, *, c, d: int = 10, **kwargs) -> int
<BoundArguments (a=1, b=2, c=3)>
{'a': 1, 'b': 2, 'c': 3}
(1, 2)
{'c': 3}
------------------------- 分隔线 -------------------------
<BoundArguments (a=1, b=2, c=3, d=10, kwargs={})>
{'a': 1, 'b': 2, 'c': 3, 'd': 10, 'kwargs': {}}
(1, 2)
{'c': 3, 'd': 10}
------------------------- 分隔线 -------------------------
1 2 3 10 {}
上面示例展示了我们还可以从已绑定好的BoundArguments对象中取实参,赋给函数来执行它。
signature.bind_partial(*args, **kwargs)
: 该方法允许我们只给部分参数绑定实参,而不像bind函数那样会报错。 有点类似于functools.partital()函数的效果。 之后我们可以对返回的BoundArguments对象再手动填加参数及实参值。
inspect.get_annotations(obj, *, globals=None, locals=None, eval_str=False)
: 获取函数类型提示。 虽然先获得Signature对象,再从里面查看parameter的属性也可以获取到,但用此函数则更方便。
import inspect
def foo(a: str, /, b, *, c, d: int=10, **kwargs) -> int:
print(a,b,c,d,kwargs)
print(inspect.get_annotations(foo))
输出结果:
inspect.getmro(cls): 获取类的mro,应该跟直接输出cls.__mro__
的效果相同。
import inspect
class Parent_1:
pass
class Parent_2:
pass
class SubClass(Parent_1, Parent_2):
pass
print(inspect.getmro(SubClass)) # (<class '__main__.SubClass'>, <class '__main__.Parent_1'>, <class '__main__.Parent_2'>, <class 'object'>)
print(SubClass.__mro__) # (<class '__main__.SubClass'>, <class '__main__.Parent_1'>, <class '__main__.Parent_2'>, <class 'object'>)
inspect.getattr_static(obj, attr, default=None): 用于获取对象的属性,而不会触发属性的动态查找机制(如 __getattr__
或 __getattribute__
)。这意味着它只会返回对象的静态属性,而不会调用任何描述符或动态属性方法。
import inspect
class Descriptor:
def __get__(self, instance, owner):
print('descriptor get')
return 'hahaha'
def __set__(self, instance, value):
print('descriptor set')
class MyClass:
class_attr = "class attribute"
desc_attr = Descriptor()
def __init__(self):
self.instance_attr = "instance attribute"
def __getattr__(self, name):
return f"Dynamic attribute: {name}"
obj = MyClass()
# 获取静态属性
print(inspect.getattr_static(obj, 'class_attr')) # 输出: class attribute
print(inspect.getattr_static(obj, 'instance_attr')) # 输出: instance attribute
# 尝试获取不存在的属性
print(inspect.getattr_static(obj, 'non_existent_attr', 'default value')) # 输出: default value
# 对比 getattr,会触发 __getattr__
print(getattr(obj, 'non_existent_attr')) # 输出: Dynamic attribute: non_existent_attr
print(getattr(obj, 'desc_attr')) # 输出: hahaha
print(inspect.getattr_static(obj, 'desc_attr', 'desc value')) # 输出: <__main__.Descriptor object at 0x0000026A4ABB9B10>
此外,inspect模块还提供了很多方法,比如用于查看解释器栈的,闭包的,生成器、协程状态的等等。 一旦我们想尝试元编程,最好先看看这个模块给我们提供了哪些能力。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构