inspect
inspect 模块是Python标准库中用于检查对象、获取源代码信息和进行内省的重要工具。
# 基本概念
内省(Introspection) 是指程序在运行时检查对象类型和属性的能力。inspect 模块提供了强大的内省功能。
# 主要功能
# 1. 对象类型检查
import inspect
# 检查对象类型
def check_object_type(obj):
if inspect.isfunction(obj):
return "函数"
elif inspect.ismethod(obj):
return "方法"
elif inspect.isclass(obj):
return "类"
elif inspect.ismodule(obj):
return "模块"
elif inspect.iscoroutinefunction(obj):
return "协程函数"
elif inspect.isgeneratorfunction(obj):
return "生成器函数"
else:
return "其他类型"
# 使用示例
print(check_object_type(len)) # 函数
print(check_object_type(str)) # 类
print(check_object_type(inspect)) # 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 2. 获取函数和类信息
import inspect
def example_function(name, age=25, *args, **kwargs):
"""这是一个示例函数"""
return f"Hello {name}, you are {age} years old"
# 获取函数签名
signature = inspect.signature(example_function)
print(signature) # (name, age=25, *args, **kwargs)
# 获取参数信息
for name, param in signature.parameters.items():
print(f"参数名: {name}")
print(f" 默认值: {param.default}")
print(f" 类型: {param.kind}")
print(f" 注释: {param.annotation}")
# 获取函数文档
doc = inspect.getdoc(example_function)
print(f"文档字符串: {doc}")
# 获取源代码
source = inspect.getsource(example_function)
print(f"源代码:\n{source}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 3. 类和对象内省
import inspect
class ExampleClass:
"""示例类"""
class_var = "类变量"
def __init__(self, name):
self.name = name
def instance_method(self):
"""实例方法"""
return f"Hello {self.name}"
@classmethod
def class_method(cls):
"""类方法"""
return "类方法"
@staticmethod
def static_method():
"""静态方法"""
return "静态方法"
# 获取类信息
print(f"类名: {ExampleClass.__name__}")
print(f"模块: {ExampleClass.__module__}")
print(f"文档: {inspect.getdoc(ExampleClass)}")
# 获取类的方法
methods = inspect.getmembers(ExampleClass, inspect.isfunction)
print("类方法:")
for name, method in methods:
print(f" {name}: {method}")
# 获取实例方法
instance = ExampleClass("Alice")
instance_methods = inspect.getmembers(instance, inspect.ismethod)
print("实例方法:")
for name, method in instance_methods:
print(f" {name}: {method}")
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 4. 调用栈和帧信息
import inspect
def get_call_stack():
"""获取当前调用栈"""
frame = inspect.currentframe()
stack = inspect.getouterframes(frame)
print("调用栈:")
for i, (frame, filename, lineno, function, code_context, index) in enumerate(stack):
print(f" {i}: {function} in {filename}:{lineno}")
if code_context:
print(f" {code_context[0].strip()}")
frame.f_locals # 当前帧的局部变量
frame.f_globals # 当前帧的全局变量
def example_function():
get_call_stack()
# 调用示例
example_function()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 5. 模块和包内省
import inspect
import os
# 获取模块信息
module_info = inspect.getmodule(os)
print(f"模块文件: {module_info.__file__}")
print(f"模块名称: {module_info.__name__}")
# 获取模块中的所有函数
module_functions = inspect.getmembers(os, inspect.isfunction)
print("模块函数:")
for name, func in module_functions[:5]: # 只显示前5个
print(f" {name}: {func}")
# 获取当前模块的方法
def get_current_module_methods():
"""获取当前模块的所有方法"""
import sys
# 获取当前模块
current_module = sys.modules[__name__]
# 获取所有方法
methods = inspect.getmembers(current_module, inspect.isfunction)
print("当前模块方法:")
for name, method in methods:
if not name.startswith('_'): # 跳过私有方法
print(f" {name}: {method}")
return methods
# 获取模块的文档
module_doc = inspect.getdoc(os)
print(f"模块文档: {module_doc[:100]}...") # 只显示前100个字符
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
27
28
29
30
31
32
33
34
35
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
27
28
29
30
31
32
33
34
35
# 6. 装饰器和元数据
import inspect
import functools
def my_decorator(func):
"""自定义装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@my_decorator
def decorated_function(x, y):
"""被装饰的函数"""
return x + y
# 检查装饰器信息
print(f"函数名: {decorated_function.__name__}")
print(f"函数文档: {inspect.getdoc(decorated_function)}")
print(f"函数签名: {inspect.signature(decorated_function)}")
# 检查是否为装饰器
def is_decorator(func):
"""检查函数是否为装饰器"""
try:
sig = inspect.signature(func)
return len(sig.parameters) == 1 and 'func' in sig.parameters
except:
return False
print(f"是否为装饰器: {is_decorator(my_decorator)}")
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
27
28
29
30
31
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
27
28
29
30
31
# 7. 实际应用场景
import inspect
# 1. 自动生成API文档
def generate_api_docs(module):
"""自动生成模块的API文档"""
functions = inspect.getmembers(module, inspect.isfunction)
docs = []
for name, func in functions:
if not name.startswith('_'): # 跳过私有函数
doc = inspect.getdoc(func)
sig = inspect.signature(func)
docs.append(f"## {name}{sig}\n\n{doc or '无文档'}\n")
return '\n'.join(docs)
# 2. 参数验证装饰器
def validate_args(func):
"""参数验证装饰器"""
sig = inspect.signature(func)
def wrapper(*args, **kwargs):
# 绑定参数
bound_args = sig.bind(*args, **kwargs)
bound_args.apply_defaults()
# 验证参数
for name, value in bound_args.arguments.items():
param = sig.parameters[name]
if param.annotation != inspect.Parameter.empty:
if not isinstance(value, param.annotation):
raise TypeError(f"参数 {name} 类型错误")
return func(*args, **kwargs)
return wrapper
@validate_args
def add_numbers(a: int, b: int) -> int:
return a + b
# 3. 调试工具
def debug_function_call(func):
"""调试函数调用的装饰器"""
def wrapper(*args, **kwargs):
frame = inspect.currentframe()
caller_frame = frame.f_back
print(f"调用函数: {func.__name__}")
print(f"调用位置: {caller_frame.f_code.co_filename}:{caller_frame.f_lineno}")
print(f"参数: args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"返回值: {result}")
return result
return wrapper
@debug_function_call
def example_debug_function(x, y):
return x * y
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# 8. 高级用法
import inspect
# 1. 动态调用函数
def dynamic_call(func_name, *args, **kwargs):
"""动态调用函数"""
# 获取当前模块的所有函数
current_module = inspect.currentframe().f_globals
if func_name in current_module:
func = current_module[func_name]
if inspect.isfunction(func):
return func(*args, **kwargs)
raise NameError(f"函数 {func_name} 不存在")
# 2. 函数重载模拟
def overload(func):
"""函数重载装饰器"""
if not hasattr(func, '_overloads'):
func._overloads = []
func._overloads.append(func)
def wrapper(*args, **kwargs):
# 根据参数类型选择正确的重载
for overload_func in func._overloads:
sig = inspect.signature(overload_func)
try:
sig.bind(*args, **kwargs)
return overload_func(*args, **kwargs)
except TypeError:
continue
raise TypeError("没有匹配的函数重载")
return wrapper
# 3. 自动测试生成器
def generate_tests(module):
"""为模块中的函数生成测试"""
tests = []
for name, obj in inspect.getmembers(module):
if inspect.isfunction(obj) and not name.startswith('_'):
sig = inspect.signature(obj)
test_code = f"""
def test_{name}():
\"\"\"测试函数 {name}\"\"\"
# TODO: 添加测试用例
pass
"""
tests.append(test_code)
return '\n'.join(tests)
# 4. 获取当前模块的详细信息
def analyze_current_module():
"""分析当前模块的详细信息"""
import sys
# 获取当前模块
current_module = sys.modules[__name__]
print(f"模块名称: {current_module.__name__}")
print(f"模块文件: {getattr(current_module, '__file__', '未知')}")
# 获取所有公共函数
public_functions = [
(name, obj) for name, obj in inspect.getmembers(current_module, inspect.isfunction)
if not name.startswith('_')
]
print(f"公共函数数量: {len(public_functions)}")
for name, func in public_functions:
doc = inspect.getdoc(func) or "无文档"
print(f" {name}: {doc[:50]}...")
# 获取所有类
classes = inspect.getmembers(current_module, inspect.isclass)
print(f"类数量: {len(classes)}")
for name, cls in classes:
if not name.startswith('_'):
print(f" {name}: {inspect.getdoc(cls) or '无文档'}")
return {
'functions': public_functions,
'classes': classes,
'module': current_module
}
# 5. 动态调用当前模块的方法
def call_module_method(method_name, *args, **kwargs):
"""动态调用当前模块的方法"""
import sys
current_module = sys.modules[__name__]
if hasattr(current_module, method_name):
method = getattr(current_module, method_name)
if inspect.isfunction(method):
return method(*args, **kwargs)
else:
raise TypeError(f"{method_name} 不是一个函数")
else:
raise AttributeError(f"模块中没有 {method_name} 方法")
# 6. 获取方法的调用信息
def get_method_info(method_name):
"""获取指定方法的详细信息"""
import sys
current_module = sys.modules[__name__]
if hasattr(current_module, method_name):
method = getattr(current_module, method_name)
info = {
'name': method_name,
'doc': inspect.getdoc(method),
'signature': str(inspect.signature(method)),
'module': method.__module__,
'is_function': inspect.isfunction(method),
'is_method': inspect.ismethod(method),
'is_coroutine': inspect.iscoroutinefunction(method),
'is_generator': inspect.isgeneratorfunction(method)
}
return info
else:
return None
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 注意事项
- 性能考虑:
inspect模块的操作可能影响性能,避免在性能关键路径中使用 - 安全性: 内省功能可能暴露敏感信息,在生产环境中谨慎使用
- 兼容性: 某些内省功能在不同Python版本中可能有差异
- 调试: 在调试模式下,某些信息可能不可用
# 最佳实践
import inspect
# 1. 使用类型提示
def process_data(data: list) -> dict:
"""处理数据函数"""
if not inspect.isclass(list) or not isinstance(data, list):
raise TypeError("参数必须是列表类型")
return {"processed": data}
# 2. 错误处理
def safe_inspect(obj):
"""安全的内省操作"""
try:
return inspect.getdoc(obj) or "无文档"
except Exception as e:
return f"获取文档失败: {e}"
# 3. 缓存结果
import functools
@functools.lru_cache(maxsize=128)
def get_function_info(func):
"""缓存函数信息"""
return {
'name': func.__name__,
'doc': inspect.getdoc(func),
'signature': str(inspect.signature(func))
}
# 4. 模块方法监控器
class ModuleMethodMonitor:
"""监控模块方法调用的工具类"""
def __init__(self, module_name=None):
import sys
self.module = sys.modules[module_name or __name__]
self.call_count = {}
def get_all_methods(self):
"""获取模块中的所有方法"""
methods = inspect.getmembers(self.module, inspect.isfunction)
return {name: method for name, method in methods if not name.startswith('_')}
def monitor_call(self, method_name):
"""监控方法调用"""
def wrapper(*args, **kwargs):
self.call_count[method_name] = self.call_count.get(method_name, 0) + 1
print(f"调用 {method_name} (第{self.call_count[method_name]}次)")
return self.module.__dict__[method_name](*args, **kwargs)
return wrapper
def get_call_statistics(self):
"""获取调用统计"""
return self.call_count.copy()
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
上次更新: 2025/07/21, 21:50:24