在 Python 3.12 之前的版本中,泛型类型检查主要依赖于静态类型检查器(如 mypy),而不是在运行时进行。TypeVar 的主要作用是为类型检查器提供类型信息,在运行时不会进行实际的类型检查。在3.12中增加了函数的类型参数元,泛型函数语法(PEP 695)需要启用特定的特性标志才能使用:在文件头添加
from __future__ import annotations。方式2:python -X specialization .\function_features_demo.py
装饰器
一、装饰器的核心概念
本质与定义
装饰器本质上是一个接收函数作为参数并返回新函数的高阶函数。它通过“包装”原函数,在其前后插入自定义逻辑(如日志记录、性能计时),实现功能的非侵入式扩展。
示例:计时装饰器统计函数执行时间,无需修改原函数代码。设计原则
- 开放封闭原则:对扩展开放(允许添加新功能),对修改封闭(不改变原代码)。
- 可复用性:通过装饰器抽离通用逻辑(如权限校验),实现代码复用。
二、装饰器的工作原理
基于闭包与高阶函数
装饰器依赖闭包(Closure)保存原函数及其执行环境,即使外层函数已执行完毕,内层包装函数仍能访问外层变量。高阶函数特性允许函数作为参数传递和返回值。语法糖与执行流程
- 使用
@decorator语法糖简化调用,等效于func = decorator(func)。 - 嵌套装饰器:多个装饰器按从下到上的顺序应用,执行时按从上到下的顺序调用。例如:
- 使用
@decorator1
@decorator2
def func(): ...
# 等价于 func = decorator1(decorator2(func))
- 参数处理
- 使用
*args和**kwargs接收任意参数,确保装饰器适配不同函数。 - 带参装饰器:需通过嵌套函数实现,外层接收参数,内层返回实际装饰器。
- 使用
def auth(role): # 外层接收参数
def decorator(func): # 内层接收函数
def wrapper(*args,**kwargs):
if check_role(role): return func(*args,**kwargs)
else: raise PermissionError
return wrapper
return decorator
三、装饰器的典型应用场景
功能增强
- 日志记录:自动记录函数调用信息(如参数、返回值)。
- 性能分析:测量函数执行时间。
- 缓存(Memoization) :使用
@functools.lru_cache缓存结果,避免重复计算。
安全与权限
- 权限验证:在函数执行前检查用户身份或权限。
- 事务管理:数据库操作前开启事务,执行后提交或回滚。
代码复用与优化
- DRY原则:通过装饰器统一处理重复逻辑(如异常捕获)。

- 类装饰器:修改类行为(如单例模式)或动态添加方法。
四、注意事项与高级技巧
保留元数据
装饰器会覆盖原函数的__name__和__doc__属性,需使用@functools.wraps(func)保留元信息,主要解决装饰器导致的函数元数据丢失问题。类装饰器
通过实现__init__(接收被装饰函数)和__call__(执行装饰逻辑)方法,以类形式实现装饰器。内置装饰器
@staticmethod/@classmethod:定义静态方法或类方法。@property:将方法转为属性访问,支持数据校验。
@wraps(func)
装饰器在包装函数时,会生成一个新的包装函数(如 wrapper),导致原函数的元数据(如 __name__、__doc__、参数签名等)被覆盖。@wraps(func) 的作用是将原函数的元数据复制到包装函数中,从而:
- 保留函数元数据:例如函数名、文档字符串、参数签名等。
- 提高代码可读性:调试时能直接看到原函数名,而非包装函数名。
- 兼容反射工具:如
help()、inspect模块等依赖元数据的工具仍能正常工作
@wraps(func) 是 functools 模块提供的装饰器,其底层调用 functools.update_wrapper,默认复制以下元数据:
__module__:函数所属模块名。__name__:函数名。__qualname__:完整限定名(如类中的方法)。__doc__:文档字符串。__annotations__:类型注解。
此外,它会更新包装函数的 __dict__ 属性(包含原函数的其他自定义属性),并添加 __wrapped__ 属性指向原函数
使用示例:
示例 1:不使用 @wraps 的元数据丢失问题
def my_decorator(func):
def wrapper(*args, **kwargs):
"""装饰器内部的包装函数"""
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""原函数的文档字符串"""
print("Hello!")
print(say_hello.__name__) # 输出:wrapper(而非 say_hello)
print(say_hello.__doc__) # 输出:装饰器内部的包装函数(而非原文档字符串)。
示例 2:使用 @wraps 保留元数据
from functools import wraps
def my_decorator(func):
@wraps(func) # 关键:复制元数据到 wrapper
def wrapper(*args, **kwargs):
"""装饰器内部的包装函数"""
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""原函数的文档字符串"""
print("Hello!")
print(say_hello.__name__) # 输出:say_hello(正确保留)
print(say_hello.__doc__) # 输出:原函数的文档字符串(正确保留)。
典型应用场景
- 日志记录:记录函数调用参数和返回值时,元数据需与原函数一致。
- 访问控制:权限校验装饰器中需保留原函数名以便日志追踪。
- 性能测试:统计函数执行时间的装饰器中需保留原函数名
from functools import wraps
def log_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"调用函数:{func.__name__},参数:{args}, {kwargs}")
result = func(*args, **kwargs)
print(f"函数返回:{result}")
return result
return wrapper
@log_decorator
def add(x: int, y: int) -> int:
"""计算两数之和"""
return x + y
print(help(add)) # 正确显示原函数签名和文档字符串。
注意事项
- 必须导入
wraps:需从functools模块导入。 - 仅对包装函数生效:需直接装饰包装函数(如
wrapper),而非外层装饰器。 - 不适用于类装饰器:需手动处理元数据
高级用法
@wraps 支持自定义复制的属性和更新的属性:
from functools import wraps
def my_decorator(func):
@wraps(func, assigned=("__name__", "__doc__"), updated=())
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
assigned:指定要复制的属性(如("__name__", "__module__"))。updated:指定要更新的属性(如__dict__)
五、总结
装饰器通过高阶函数和闭包机制,为Python提供了优雅的功能扩展方式。其应用覆盖日志、性能优化、安全控制等场景,且支持参数化、嵌套使用及类装饰器等高级特性。正确使用装饰器需注意元数据保留和设计模式,以提升代码的可维护性与灵活性。
高阶函数
Python中的高阶函数是一种重要的编程范式,其核心机制在于将函数视为“一等公民”,允许函数作为参数传递或返回值,从而实现更灵活、抽象的代码设计。以下从概念、机制、应用三方面进行深入解析:
一、高阶函数的概念
高阶函数(Higher-order Function)需满足以下条件之一:
- 接受函数作为参数:例如
map()、filter()等内置函数。 - 返回函数作为结果:例如闭包、装饰器的实现。
- 同时满足上述两点:如同时接收函数参数并返回新函数的装饰器。
Python中函数是“一等公民”,可像普通变量一样被赋值、传递和返回,这是高阶函数的基础。
二、高阶函数的机制
1. 函数作为参数传递
- 内置高阶函数:
map(function, iterable):对可迭代对象的每个元素应用函数,返回迭代器。例如,map(lambda x: x**2, [1,2,3])生成平方序列。filter(function, iterable):根据函数返回值(True/False)筛选元素。例如,筛选奇数:filter(lambda x: x%2 !=0, [1,2,3])。sorted(iterable, key, reverse):自定义排序规则。例如按绝对值排序:sorted([-3,1,2], key=abs)。reduce(function, iterable):累积计算(需从functools导入)。例如求和:reduce(lambda x,y: x+y, [1,2,3])结果为6。
2. 函数作为返回值
- 闭包(Closure) :内部函数捕获外部函数的变量。例如:
def outer():
x = 10
def inner():
return x + 5
return inner
调用outer()返回inner函数,且inner仍能访问x。
- 装饰器(Decorator) :在不修改原函数代码的情况下增强功能。例如计时装饰器:
def timer(func):
def wrapper(*args):
start = time.time()
result = func(*args)
print(f"Time: {time.time() - start}")
return result
return wrapper
使用@timer语法修饰目标函数。
3. 嵌套函数与作用域
函数内部可定义子函数,子函数可访问外层函数的变量。例如闭包和装饰器均依赖此特性。
三、高阶函数的应用场景
1. 函数式编程
- 使用
map、filter、reduce等处理数据流,代码简洁高效。例如批量转换数据格式:list(map(str.upper, ["a", "b"]))生成["A", "B"]。
2. 装饰器模式
- 动态添加功能(如日志、权限校验)。例如缓存装饰器可缓存函数计算结果。
3. 回调函数
- 将函数作为参数传递给异步事件处理函数。例如GUI编程中按钮点击事件的回调。
4. 匿名函数(lambda)
- 与高阶函数结合简化代码。例如:
sorted([("b",2), ("a",1)], key=lambda x: x[1])按元组第二个元素排序。
5. 偏函数(Partial Function)
- 固定部分参数生成新函数。例如:
from functools import partial; int2 = partial(int, base=2)将int()的进制固定为二进制。
6. 闭包与状态封装
- 实现有状态的函数。例如计数器:
def counter():
count = 0
def inc():
nonlocal count
count +=1
return count
return inc
每次调用inc()会递增count。
闭包允许内部函数访问外部函数的变量,但直接修改外层变量时必须使用
nonlocal声明,否则会触发UnboundLocalError错误
变量作用域的默认行为:
- 当内部函数仅读取外层变量时(例如
print(count)),可以直接访问,无需声明nonlocal。 - 但若内部函数尝试修改外层变量(例如
count += 1),Python会将其视为新的局部变量,而非闭包变量。此时,由于局部变量count未被初始化就直接操作,会触发UnboundLocalError。
- 当内部函数仅读取外层变量时(例如
nonlocal的作用:nonlocal关键字明确告诉解释器:“此变量不属于当前作用域,请向上查找最近的匹配变量”。这样,count会被识别为外层函数的局部变量,而非内部函数的局部变量。- 例如在用户提供的代码中,通过
nonlocal count声明后,count += 1才正确引用并修改外层函数的count变量,形成闭包。
四、高阶函数的优势
- 代码抽象:通过将函数作为参数,隐藏具体实现,提升代码复用性。
- 灵活性:动态组合功能(如装饰器),适应需求变化。
- 简洁性:结合lambda和内置函数,减少冗余代码。
总结
高阶函数是Python函数式编程的核心,其机制通过函数传递、闭包和装饰器等实现,应用场景涵盖数据处理、功能扩展和代码抽象。熟练掌握高阶函数可显著提升代码质量与开发效率。
函数特性示例详解
from __future__ import annotations
"""Python函数特性详解示例
本模块展示了Python函数的各种高级特性,包括:
1. 泛型函数与类型形参(Python 3.12+)
2. 默认参数陷阱及解决方案
3. 类型标注及其应用
4. 参数传递规则
5. 函数对象及其属性
"""
from typing import TypeVar, Generic, Optional, Union, Any
from functools import wraps
import inspect
import time
# 1. 泛型函数示例
T = TypeVar('T')
def process[T](data: list[T]) -> T | None:
"""泛型函数示例
在Python 3.12+中,可以使用类型形参语法定义泛型函数
底层实现:函数对象会包含__type_params__属性存储类型参数
"""
# 获取类型参数信息
type_params = process.__type_params__
print(f"类型参数: {type_params}")
return data[0] if data else None
# 2. 默认参数陷阱演示
class DefaultArgsDemo:
"""演示默认参数的陷阱和解决方案"""
@staticmethod
def buggy_append(item: Any, lst: list = []) -> list:
"""有缺陷的默认参数实现
默认参数在函数定义时就被求值,而不是在调用时,这个默认值会成为函数对象的一个属性(存储在 __defaults__ 中)
这个默认值会在整个程序运行期间一直存在,而不是每次调用时重新创建,所有调用共享同一个列表对象
设计原因:- 函数在 Python 中是一等对象,默认参数是函数对象的属性,而不是局部变量
它在某些场景下很有用,比如实现缓存或记忆化
"""
lst.append(item)
return lst
@staticmethod
def safe_append(item: Any, lst: Optional[list] = None) -> list:
"""安全的默认参数实现
使用None作为标记,在函数调用时创建新的列表
- None 是不可变对象,作为默认值是安全的 - 每次调用函数时都会创建新的列表
"""
if lst is None:
lst = [] # 每次调用时创建新的列表
lst.append(item)
return lst
# 3. 参数传递规则示例
def demonstrate_args(
pos_only_arg: str, /, # 仅位置参数
standard_arg: int, # 标准参数
*args: tuple[str, ...], # 可变位置参数
kw_only_arg: float = 1.0, # 仅关键字参数
**kwargs: Any # 可变关键字参数
) -> None:
"""展示不同类型的参数传递
参数解析过程:
1. 首先处理位置参数
2. 然后处理关键字参数
3. 多余的位置参数存入*args
4. 多余的关键字参数存入**kwargs
"""
print(f"位置参数: {pos_only_arg}")
print(f"标准参数: {standard_arg}")
print(f"可变位置参数: {args}")
print(f"仅关键字参数: {kw_only_arg}")
print(f"可变关键字参数: {kwargs}")
# 4. 函数对象及属性研究
def function_introspection_demo():
"""演示函数对象的内省机制"""
def example_func(a: int, b: str = "default") -> None:
"""示例函数"""
pass
# 显示函数的各种属性
print(f"函数名: {example_func.__name__}")
print(f"文档字符串: {example_func.__doc__}")
print(f"类型注解: {example_func.__annotations__}")
print(f"默认参数: {example_func.__defaults__}")
print(f"所在模块: {example_func.__module__}")
# 使用inspect模块获取更多信息
sig = inspect.signature(example_func)
print(f"函数签名: {sig}")
for name, param in sig.parameters.items():
print(f"参数 {name}: {param.kind}, 默认值: {param.default}")
# 5. 装饰器与闭包示例
def timing_decorator(func):
"""测量函数执行时间的装饰器
展示了闭包和装饰器的实现原理
"""
@wraps(func) # 保留原函数的元数据
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__} 执行时间: {end - start:.6f} 秒")
return result
return wrapper
@timing_decorator
def slow_function(n: int) -> int:
"""测试装饰器的示例函数"""
time.sleep(n)
return n
# TypeVar(用于定义泛型类型变量) 示例
from typing import TypeVar, List, Sequence
# 基础 TypeVar
T = TypeVar('T') # 可以是任何类型
S = TypeVar('S', bound=str) # 限制为 str 或其子类
N = TypeVar('N', int, float) # 限制为 int 或 float
K = TypeVar('K', bound='BaseClass') # 限制为 BaseClass 或其子类
def first_element[T](lst: List[T]) -> T | None:
"""返回列表的第一个元素"""
return lst[0] if lst else None
def string_operation[S](text: S) -> S:
"""只接受字符串类型的操作"""
return text
def number_operation[N](num: N) -> N:
"""只接受数字类型的操作"""
return num
class BaseClass:
pass
class SubClass(BaseClass):
pass
def process_base[K](item: K) -> K:
"""只接受 BaseClass 及其子类的操作"""
return item
def demonstrate_typevar():
"""演示 TypeVar 的各种用法"""
# 基础 TypeVar 示例
print(first_element([1, 2, 3])) # 输出: 1
print(first_element(["a", "b"])) # 输出: "a"
# 带边界的 TypeVar
print(string_operation("hello")) # 正确
# print(string_operation(123)) # 类型检查器会报错
# 带约束的 TypeVar
print(number_operation(42)) # 正确
print(number_operation(3.14)) # 正确
# print(number_operation("123")) # 类型检查器会报错
# 类型边界示例
base = BaseClass()
sub = SubClass()
print(process_base(base)) # 正确
print(process_base(sub)) # 正确
# print(process_base("wrong")) # 类型检查器会报错
# 6. 高阶函数示例
from typing import Callable, TypeVar, Any, Type # Added Type import
R = TypeVar('R') # 返回值类型
T = TypeVar('T') # 输入参数类型
# 检查泛型函数定义
def process[T](data: list[T]) -> T | None:
return data[0] if data else None
def first_element[T](lst: List[T]) -> T | None:
return lst[0] if lst else None
"""
- [T, R] :定义了两个类型参数,T和R分别代表不同的类型
- f: Callable[[T], R] :第一个参数f是一个函数,接收T类型参数,返回R类型结果
- g: Callable[[Any], T] :第二个参数g是一个函数,接收任意类型参数,返回T类型结果
- -> Callable[[Any], R] :返回一个新函数,这个函数接收任意类型参数,返回R类型结果
def add_one(x: int) -> int: # f函数,T=int, R=int
return x + 1
def double(x: int) -> int: # g函数
return x * 2
# compose(add_one, double)(3) 等价于 add_one(double(3))
result = compose(add_one, double)(3) # 结果为7:先3*2=6,再6+1=7
"""
def compose[T, R](f: Callable[[T], R], g: Callable[[Any], T]) -> Callable[[Any], R]:
"""函数组合:返回一个新函数 h(x) = f(g(x))"""
def composed_function(x: Any) -> R:
return f(g(x))
return composed_function
"""
这是一个装饰器工厂,用于创建具有重试功能的装饰器。
- [T] :定义一个类型参数,代表被装饰函数的返回类型
- times: int :重试次数
- on_exception: Type[Exception] :指定需要捕获的异常类型
- -> Callable[[Callable[..., T]], Callable[..., T]] :返回一个装饰器函数,这个装饰器接收并返回相同签名的函数
最外层 Callable[X, Y] 表示一个函数,其中:
- X 是参数类型列表
- Y 是返回值类型
Callable[..., T] 中的 ... 表示接受任意数量和类型的参数, T 表示返回值类型
@retry[str](times=3) # 指定返回类型为str,最多重试3次
def unstable_operation() -> str:
if random.random() < 0.7: # 70%概率失败
raise ConnectionError("连接失败")
return "操作成功"
"""
def retry[T](times: int, on_exception: Type[Exception] = Exception) -> Callable[[Callable[..., T]], Callable[..., T]]:
"""创建一个装饰器,在异常时重试指定次数,返回的装饰器函数decorator接收一个函数func,并返回包装后的函数wrapper。这里使用了@wraps(func)来保留原函数的元数据"""
def decorator(func: Callable[..., T]) -> Callable[..., T]: #- 接收原始函数 func 作为参数- 返回包装后的函数 wrapper
@wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> T: #- 使用 @wraps(func) 保留原函数的元数据 - 实现重试逻辑 - *args 和 **kwargs 用于接收任意参数
for attempt in range(times):
try:
return func(*args, **kwargs)
except on_exception as e:
if attempt == times - 1: # 最后一次尝试
raise e
print(f"尝试 {attempt + 1} 失败,准备重试...")
raise RuntimeError("不应该到达这里")
return wrapper
return decorator
def demonstrate_higher_order_functions():
"""演示高阶函数的使用"""
# 1. 函数组合示例
def double(x: int) -> int:
return x * 2
def add_one(x: int) -> int:
return x + 1
# 组合函数:先double再add_one
double_then_add = compose(add_one, double)
print(f"double_then_add(3) = {double_then_add(3)}") # 应该输出7 (3*2+1)
# 2. 重试装饰器示例
@retry(times=3)
def unstable_operation() -> str:
"""模拟一个不稳定的操作"""
import random
if random.random() < 0.7: # 70%的概率失败
raise ConnectionError("连接失败")
return "操作成功"
try:
result = unstable_operation()
print(f"操作结果: {result}")
except Exception as e:
print(f"最终失败: {e}")
# 在main函数中添加高阶函数演示
def main():
"""运行所有示例"""
# 1. 测试泛型函数
print("\n1. 泛型函数示例:")
print("函数的类型参数信息:")
print(f"类型参数列表: {process.__type_params__}") # 输出类型参数信息
print("\n具体调用示例:")
#print(process[int]([1, 2, 3]))新语法但报错了
print(process([1, 2, 3]))
#print(process[str](["a", "b"]))
print(process(["a", "b"]))
# 2. 测试默认参数
print("\n2. 默认参数示例:")
demo = DefaultArgsDemo()
print("有缺陷的实现:")
# 在函数定义时,空列表[]就被创建并绑定到函数对象上
print(demo.buggy_append.__defaults__) # 输出: ([],)
print(demo.buggy_append(1))
print(demo.buggy_append(2)) # 会看到累积效果
print("\n安全的实现:")
print(demo.safe_append(1))
print(demo.safe_append(2)) # 每次都是新列表
# 3. 测试参数传递
print("\n3. 参数传递示例:")
demonstrate_args("pos", 42, "extra1", "extra2",
kw_only_arg=2.0, extra_kw="value")
# 4. 函数内省
print("\n4. 函数内省示例:")
function_introspection_demo()
# 5. 装饰器测试
print("\n5. 装饰器示例:")
slow_function(1)
# 添加 TypeVar 演示
print("\n6. TypeVar 示例:")
demonstrate_typevar()
# 添加高阶函数演示
print("\n7. 高阶函数示例:")
demonstrate_higher_order_functions()
if __name__ == "__main__":
main()
装饰器工厂(如 retry[T])的作用是动态生成装饰器函数。其结构通常为:
def factory(...) -> Callable[[原函数类型], 装饰后函数类型]:
def decorator(func: 原函数类型) -> 装饰后函数类型:
def wrapper(...) -> 返回值类型:
# 装饰逻辑
return wrapper
return decorator
工厂返回值:decorator 函数,它接受原函数并返回包装后的函数。 类型标注的意义:通过 Callable 链式标注,明确装饰器工厂返回的是一个“函数→函数”的转换器
