Python 提供了丰富的文档和内省机制,使开发者能够编写自解释的代码并在运行时检查对象属性。本教程详细介绍了函数文档、类型注释和内省技术。
Python 使用三引号字符串('''
或 """
)作为文档字符串(docstring),用于描述模块、类、方法或函数的功能。
def calculate_area(radius):
"""计算圆的面积。
Args:
radius (float): 圆的半径
Returns:
float: 圆的面积
"""
import math
return math.pi * radius ** 2
help()
是 Python 的内置函数,用于查看对象的文档。它会显示从 docstring 中提取的信息。
# 模块级别的 help
import math
help(math) # 显示整个 math 模块的文档
# 函数级别的 help
help(math.sin) # 显示 sin 函数的文档
# 自定义函数的 help
def greet(name):
"""向指定的人打招呼。
Args:
name: 要问候的人的名字
Returns:
包含问候语的字符串
"""
return f"你好,{name}!"
help(greet) # 显示 greet 函数的文档
Python 3.5+ 支持类型注释,帮助开发者和工具理解代码中变量和函数的预期类型。
def add_numbers(a: int, b: int) -> int:
"""将两个整数相加。
Args:
a: 第一个整数
b: 第二个整数
Returns:
两个整数的和
"""
return a + b
# 带有默认值的类型注释
def greet_user(name: str = "用户") -> str:
return f"你好,{name}!"
对于更复杂的类型,可以使用 typing
模块。
from typing import List, Dict, Tuple, Optional, Union, Any
def process_data(items: List[int]) -> Dict[str, Any]:
"""处理整数列表并返回结果字典。"""
return {
"count": len(items),
"sum": sum(items),
"average": sum(items) / len(items) if items else 0
}
def get_user_info(user_id: int) -> Optional[Dict[str, Union[str, int]]]:
"""获取用户信息,如果用户不存在则返回 None。"""
# 示例实现
users = {1: {"name": "张三", "age": 30}}
return users.get(user_id)
# 函数类型注释
def apply_operation(x: int, operation: Callable[[int], int]) -> int:
"""对整数应用指定的操作。"""
return operation(x)
内省允许程序在运行时检查对象的类型和属性。
def basic_introspection_demo():
"""演示基本的内省技术。"""
# 检查对象类型
number = 42
text = "Hello"
print(f"number 的类型: {type(number)}")
print(f"text 的类型: {type(text)}")
# 列出对象的属性和方法
print(f"\ntext 的方法和属性:")
print(dir(text)[:5]) # 只显示前5个
# 检查对象是否具有特定属性
print(f"\n'upper' 是否是 text 的属性: {'upper' in dir(text)}")
# 访问文档字符串
print(f"\n当前函数的文档字符串: {basic_introspection_demo.__doc__}")
inspect
模块提供了更强大的内省功能。
import inspect
def advanced_introspection_demo():
"""演示使用 inspect 模块的高级内省技术。"""
def sample_function(a: int, b: str = "默认值") -> bool:
"""一个带有类型注释的示例函数。"""
return True
# 获取函数签名
sig = inspect.signature(sample_function)
print(f"函数签名: {sig}")
# 获取参数信息
print("\n参数详情:")
for name, param in sig.parameters.items():
print(f" {name}: {param.annotation}, 默认值={param.default}")
# 获取返回类型注释
print(f"返回类型: {sig.return_annotation}")
# 获取源代码
print(f"\n函数源代码:\n{inspect.getsource(sample_function)}")
# 获取定义位置
print(f"\n函数定义位置: {inspect.getfile(sample_function)}, 行 {inspect.getsourcelines(sample_function)[1]}")
下面是一个综合示例,演示了如何将文档、类型注释和内省结合使用:
from typing import List, Dict, Any, Optional
import inspect
class DataAnalyzer:
"""数据分析工具类。
该类演示了如何结合使用文档字符串、类型注释和内省技术。
Attributes:
name: 分析器名称
data_source: 数据来源
results: 分析结果缓存
"""
def __init__(self, name: str, data_source: str):
"""初始化数据分析器。
Args:
name: 分析器名称
data_source: 数据来源标识
"""
self.name = name
self.data_source = data_source
self.results: Dict[str, Any] = {}
def analyze(self, dataset: List[float]) -> Dict[str, float]:
"""分析数据集并返回统计结果。
Args:
dataset: 要分析的数值列表
Returns:
包含统计结果的字典
Raises:
ValueError: 如果数据集为空
"""
if not dataset:
raise ValueError("数据集不能为空")
result = {
"count": len(dataset),
"mean": sum(dataset) / len(dataset),
"min": min(dataset),
"max": max(dataset)
}
# 计算标准差
mean = result["mean"]
variance = sum((x - mean) ** 2 for x in dataset) / len(dataset)
result["std_dev"] = variance ** 0.5
# 保存结果到缓存
self.results["latest"] = result
return result
def get_metadata(self) -> Dict[str, str]:
"""返回分析器元数据。
Returns:
包含元数据的字典
"""
return {
"name": self.name,
"data_source": self.data_source,
"has_results": "yes" if self.results else "no"
}
def inspect_class(cls) -> None:
"""检查并显示类的详细信息。
Args:
cls: 要检查的类
"""
print(f"类名: {cls.__name__}")
print(f"文档: {cls.__doc__}")
print("\n方法:")
for name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
if not name.startswith('_') or name == '__init__':
sig = inspect.signature(method)
print(f"\n {name}{sig}")
if method.__doc__:
print(f" 文档: {method.__doc__.strip()}")
print(" 参数:")
for param_name, param in sig.parameters.items():
if param_name != 'self':
print(f" - {param_name}: {param.annotation}")
print(f" 返回类型: {sig.return_annotation}")
if __name__ == "__main__":
# 演示类的内省
print("===== 检查 DataAnalyzer 类 =====\n")
inspect_class(DataAnalyzer)
# 使用该类
print("\n\n===== 使用 DataAnalyzer 类 =====\n")
analyzer = DataAnalyzer("温度分析器", "weather_station_1")
result = analyzer.analyze([21.5, 22.0, 23.1, 20.8, 22.5])
print(f"分析结果: {result}")
print(f"元数据: {analyzer.get_metadata()}")
# 使用内置 help 函数
print("\n\n===== 内置 help 输出 =====\n")
help(DataAnalyzer.analyze)