Python装饰器完全指南:从入门到元编程高级模式🎯 本文系统性地讲解Python装饰器,从最基础的函数装饰器到类装饰器、描述符协议、元类装饰器,再到生产中常用的日志、缓存、认证、限流装饰器实战。每一行代码都经过验证。前言装饰器是Python最优雅的特性之一,也是面试的高频考点。但大多数教程只讲了冰山一角。本文将带你从"会用@语法"到"理解装饰器背后的元编程原理",最终掌握生产级装饰器的编写技巧。一、装饰器的本质:一切都是对象1.1 函数是一等公民# 在Python中,函数是对象,可以赋值、传递、作为返回值defgreet(name):returnf"Hello,{name}!"# 1. 函数可以赋值给变量say_hello=greetprint(say_hello("World"))# Hello, World!# 2. 函数可以作为参数传递defcall_func(func,arg):returnfunc(arg)print(call_func(greet,"Python"))# Hello, Python!# 3. 函数可以作为返回值defget_greeter():definner(name):returnf"Hi,{name}!"returninner greeter=get_greeter()print(greeter("Erpan"))# Hi, Erpan!# 4. 函数有属性print(greet.__name__)# greetprint(greet.__doc__)# None1.2 装饰器就是高阶函数# 最简单的装饰器defmy_decorator(func):defwrapper(*args,**kwargs):print("函数调用前")result=func(*args,**kwargs)print("函数调用后")returnresultreturnwrapper# 手动应用装饰器defsay_hello():print("Hello!")say_hello=my_decorator(say_hello)say_hello()# @语法糖(完全等价)@my_decoratordefsay_hello():print("Hello!")say_hello()1.3 functools.wraps的重要性fromfunctoolsimportwraps# ❌ 错误:不使用wrapsdefbad_decorator(func):defwrapper(*args,**kwargs):returnfunc(*args,**kwargs)returnwrapper@bad_decoratordefexample():"""这是示例函数"""passprint(example.__name__)# wrapper ← 丢失了原始函数名!print(example.__doc__)# None ← 丢失了文档字符串!# ✅ 正确:使用wrapsdefgood_decorator(func):@wraps(func)# 关键!保留原始函数的元信息defwrapper(*args,**kwargs):returnfunc(*args,**kwargs)returnwrapper@good_decoratordefexample():"""这是示例函数"""passprint(example.__name__)# example ✓print(example.__doc__)# 这是示例函数 ✓二、带参数的装饰器2.1 装饰器工厂模式fromfunctoolsimportwrapsimporttime# 带参数的装饰器 = 装饰器工厂函数defretry(max_attempts:int=3,delay:float=1.0,exceptions:tuple=(Exception,)):""" 重试装饰器 参数: max_attempts: 最大重试次数 delay: 重试间隔(秒) exceptions: 需要重试的异常类型 """defdecorator(func):@wraps(func)defwrapper(*args,**kwargs):last_exception=Noneforattemptinrange(1,max_attempts+1):try:returnfunc(*args,**kwargs)exceptexceptionsase:last_exception=eifattemptmax_attempts:print(f"第{attempt}次调用失败:{e},{delay}秒后重试...")time.sleep(delay)else:print(f"第{attempt}次调用失败:{e},已达最大重试次数")raiselast_exceptionreturnwrapperreturndecorator# 使用@retry(max_attempts=3,delay=0.5,exceptions=(ConnectionError,TimeoutError))deffetch_data(url:str):"""从URL获取数据"""importrandomifrandom.random()0.7:raiseConnectionError("连接超时")return{"status":"ok"}# 等价于:# fetch_data = retry(max_attempts=3, delay=0.5)(fetch_data)2.2 可选参数装饰器fromfunctoolsimportwrapsdefflexible_decorator(func=None,*,prefix="LOG",level="INFO"):""" 灵活的装饰器,支持有参数和无参数两种用法 用法1: @flexible_decorator 用法2: @flexible_decorator(prefix="DEBUG", level="DEBUG") """defdecorator(f):@wraps(f)defwrapper(*args,**kwargs):print(f"[{prefix}][{level}] Calling{f.__name__}")returnf(*args,**kwargs)returnwrapper# 无参数调用:@flexible_decoratoriffuncisnotNone:returndecorator(func)# 有参数调用:@flexible_decorator(prefix="DEBUG")returndecorator# 使用@flexible_decoratordefno_args():pass@flexible_decorator(prefix="DEBUG",level="WARNING")defwith_args():passno_args()# [LOG][INFO] Calling no_argswith_args()# [DEBUG][WARNING] Calling with_args三、类装饰器3.1 用类实现装饰器importtimefromfunctoolsimportwrapsfromcollectionsimportdefaultdictclassTimer:""" 计时装饰器(类实现) 支持统计多次调用的平均耗时 """# 类级别的统计存储_stats=defaultdict(list)def__init__(self,func):wraps(func)(self)# 等价于 functools.wrapsself._func=funcdef__call__(self,*args,**kwargs):start=time.perf_counter()result=self._func(*args,**kwargs)elapsed=time.perf_counter()-start Timer._stats[self._func.__name__].append(elapsed)returnresultdef__get__(self,obj,objtype=None):"""支持实例方法"""ifobjisNone:returnselfreturnlambda*args,**kwargs:self(obj,*args,**kwargs)@classmethoddefget_stats(cls):"""获取所有被装饰函数的统计信息"""stats={