当前位置: 首页 > news >正文

Python装饰器详解和默认装饰器

文章目录

        • python装饰器
          • Python装饰器详解
          • 装饰器的基本结构
          • 带参数的装饰器
          • 保留原始函数元信息
          • 类装饰器
          • 常见应用场景
        • 默认装饰器
          • **1. `@staticmethod` - 静态方法**
          • **2. `@classmethod` - 类方法**
          • **3. `@property` - 属性装饰器**
          • **4. `@functools.lru_cache` - 缓存装饰器**
          • **5. `@functools.wraps` - 保留函数元信息**
          • **6. `@contextlib.contextmanager` - 上下文管理器**
          • **7. `@dataclass` - 数据类装饰器(Python 3.7+)**
          • **8. `@abc.abstractmethod` - 抽象方法(Python的抽象基类)**
          • **总结**

python装饰器
Python装饰器详解

装饰器是Python中一种强大的语法糖,允许你在不修改原有函数代码的情况下,扩展其功能。装饰器本质上是一个函数,它接收另一个函数作为参数,并返回一个新的函数。

装饰器的基本结构

一个简单的装饰器可以这样实现:

def my_decorator(func):def wrapper(*args, **kwargs):# 在调用原始函数之前执行的代码print("在函数执行前做一些事情")# 调用原始函数result = func(*args, **kwargs)# 在调用原始函数之后执行的代码print("在函数执行后做一些事情")return resultreturn wrapper@my_decorator
def say_hello(name):print(f"你好, {name}!")return f"已向{name}打招呼"# 调用被装饰的函数
result = say_hello("张三")
print(result)

上面的代码中:

  • my_decorator 是一个装饰器函数,它接收一个函数作为参数
  • wrapper 是一个内部函数,它接收任意数量的位置参数和关键字参数
  • *args**kwargs 确保装饰器可以应用于任何函数
  • 装饰器返回 wrapper 函数,替代了原始函数
带参数的装饰器

如果需要传递参数给装饰器,可以创建一个返回装饰器的函数:

def repeat(n):def decorator(func):def wrapper(*args, **kwargs):results = []for _ in range(n):result = func(*args, **kwargs)results.append(result)return resultsreturn wrapperreturn decorator@repeat(3)
def greet(name):return f"你好, {name}!"# 调用被装饰的函数
messages = greet("李四")
print(messages)  # 输出: ['你好, 李四!', '你好, 李四!', '你好, 李四!']
保留原始函数元信息

当使用装饰器时,原始函数的元信息(如名称、文档字符串等)会被替换为包装器的信息。可以使用 functools.wraps 来保留这些信息:

import functoolsdef my_decorator(func):@functools.wraps(func)def wrapper(*args, **kwargs):print(f"调用函数 {func.__name__}")result = func(*args, **kwargs)print(f"函数 {func.__name__} 执行完毕")return resultreturn wrapper@my_decorator
def add(a, b):"""计算两个数的和"""return a + bprint(add.__name__)  # 输出: add
print(add.__doc__)   # 输出: 计算两个数的和
类装饰器

除了函数装饰器,还可以使用类来创建装饰器:

class CountCalls:def __init__(self, func):self.func = funcself.num_calls = 0def __call__(self, *args, **kwargs):self.num_calls += 1print(f"第 {self.num_calls} 次调用 {self.func.__name__}")return self.func(*args, **kwargs)@CountCalls
def say_hi():print("Hi!")say_hi()  # 输出: 第 1 次调用 say_hi
say_hi()  # 输出: 第 2 次调用 say_hi
常见应用场景

装饰器在实际开发中有很多用途:

  1. 日志记录:记录函数调用和参数
  2. 性能测试:测量函数执行时间
  3. 缓存:实现函数结果的缓存
  4. 权限验证:检查用户权限
  5. 重试机制:函数失败时自动重试

下面是一个记录函数执行时间的装饰器示例:

import time
import functoolsdef timer(func):@functools.wraps(func)def wrapper(*args, **kwargs):start_time = time.perf_counter()result = func(*args, **kwargs)end_time = time.perf_counter()print(f"函数 {func.__name__} 执行时间: {end_time - start_time:.4f} 秒")return resultreturn wrapper@timer
def calculate_sum(n):return sum(range(n + 1))result = calculate_sum(1000000)
print(f"结果: {result}")

通过这些示例,你应该能够理解装饰器的基本原理并开始手写自己的装饰器了。装饰器的核心是闭包函数式编程的概念,掌握它们将大大提升你的Python编程能力。

默认装饰器

Python内置了多个实用的装饰器,它们广泛应用于日常编程中。以下是一些常用的默认装饰器及其应用场景:

1. @staticmethod - 静态方法
  • 作用:将类中的方法转换为静态方法,使其不依赖于类实例或类本身。
  • 特点
    • 无需传入 selfcls 参数。
    • 无法访问类或实例的属性和方法。
  • 应用场景:与类相关但不依赖于类状态的工具函数。
class MathUtils:@staticmethoddef add(a, b):return a + b# 使用方式
print(MathUtils.add(3, 5))  # 无需创建实例
2. @classmethod - 类方法
  • 作用:将方法绑定到类而非实例,接收 cls 参数(类本身)。
  • 特点
    • 可通过类或实例调用。
    • 常用于创建工厂方法或修改类属性。
  • 应用场景:工厂模式、替代构造函数。
class Person:def __init__(self, name, age):self.name = nameself.age = age@classmethoddef from_birth_year(cls, name, birth_year):age = 2023 - birth_yearreturn cls(name, age)  # 使用cls创建实例# 使用方式
person = Person.from_birth_year("张三", 1990)
print(person.age)  # 33
3. @property - 属性装饰器
  • 作用:将方法转换为只读属性,简化属性访问。
  • 特点
    • 调用时无需括号(如 obj.prop 而非 obj.prop())。
    • 可与 @prop.setter@prop.deleter 组合使用,实现属性的修改和删除。
  • 应用场景:计算属性、数据验证、属性访问控制。
class Circle:def __init__(self, radius):self._radius = radius@propertydef radius(self):return self._radius@radius.setterdef radius(self, value):if value < 0:raise ValueError("半径不能为负")self._radius = value@propertydef area(self):return 3.14 * self._radius ** 2# 使用方式
c = Circle(5)
print(c.area)    # 78.5
c.radius = 10    # 自动触发setter验证
4. @functools.lru_cache - 缓存装饰器
  • 作用:缓存函数的返回值,避免重复计算,提升性能。
  • 特点
    • 基于最近最少使用(LRU)算法。
    • 适用于纯函数(输入相同则输出相同)。
  • 应用场景:递归函数、耗时计算、API调用。
import functools@functools.lru_cache(maxsize=128)
def fibonacci(n):if n <= 1:return nreturn fibonacci(n-1) + fibonacci(n-2)# 使用方式
print(fibonacci(50))  # 秒级响应(缓存优化)
5. @functools.wraps - 保留函数元信息
  • 作用:在自定义装饰器中保留被装饰函数的元信息(如名称、文档字符串)。
  • 特点
    • 避免装饰器覆盖原函数的 __name____doc__ 等属性。
  • 应用场景:自定义装饰器的开发。
import functoolsdef my_decorator(func):@functools.wraps(func)  # 保留原函数元信息def wrapper(*args, **kwargs):return func(*args, **kwargs)return wrapper@my_decorator
def example():"""这是一个示例函数"""passprint(example.__name__)  # 输出 "example",而非 "wrapper"
print(example.__doc__)   # 输出 "这是一个示例函数"
6. @contextlib.contextmanager - 上下文管理器
  • 作用:将生成器函数转换为上下文管理器(支持 with 语句)。
  • 特点
    • 通过 yield 分隔上下文的进入和退出逻辑。
  • 应用场景:资源管理、异常处理。
from contextlib import contextmanager@contextmanager
def open_file(filename, mode):f = open(filename, mode)try:yield f  # 进入with语句时返回资源finally:f.close()  # 退出with语句时释放资源# 使用方式
with open_file("test.txt", "w") as f:f.write("Hello, world!")
7. @dataclass - 数据类装饰器(Python 3.7+)
  • 作用:自动生成 __init____repr____eq__ 等方法,简化数据类定义。
  • 特点
    • 减少样板代码,提升开发效率。
  • 应用场景:纯数据存储类。
from dataclasses import dataclass@dataclass
class Point:x: floaty: float# 自动生成__init__
p = Point(3, 4)
print(p)  # 自动生成__repr__: Point(x=3, y=4)
8. @abc.abstractmethod - 抽象方法(Python的抽象基类)
  • 作用:定义抽象方法,强制子类实现该方法。
  • 特点
    • 含抽象方法的类无法实例化,必须被子类继承并实现所有抽象方法。
  • 应用场景:接口定义、框架设计。
from abc import ABC, abstractmethodclass Shape(ABC):@abstractmethoddef area(self):passclass Circle(Shape):def __init__(self, radius):self.radius = radiusdef area(self):  # 必须实现抽象方法return 3.14 * self.radius ** 2
总结

这些内置装饰器覆盖了面向对象编程、性能优化、代码简洁性等多个方面。合理使用它们可以显著提升代码质量和开发效率。此外,Python社区也提供了许多第三方装饰器(如Flask@app.route、Django的@login_required),进一步扩展了装饰器的应用场景。

相关文章:

  • 【大模型推理】CTA与SM关系
  • 【解决方案】Kali 2022.3修复仓库密钥一键安装docker,docker compose
  • frp搭建踩坑....
  • 习惯养成、亲子互动、分龄对话,声网AI撑起儿童产品三大核心
  • 提升系统效率:电脑自动关机解决方案
  • 父亲节至,感恩如山父爱。
  • 重定向与缓冲区:C语言IO的奥秘(模拟封装glibc)
  • 【BrowserTools MCP:让 AI 直接调试你的网页应用】
  • 【无标题】二维拓扑色动力学模型:数学物理基础与可行性论证
  • Fiori 初学记录----怎么调用后端系统odata 服务实现简单的CURD
  • App渠道效果怎么统计和对比,有哪些实用方法和工具?
  • 一个用专业知识库与多层RAG打造调研报告的Agent
  • 封装python的docker镜像
  • 图纸管理教程-4 物料关联产品多,如何管理发布、变更?
  • Ubuntu VMware虚拟机卡在/dev/sda1
  • 编译器基础概念
  • 【MPC】模型预测控制笔记 (2):约束MPC
  • HTML+CSS实现的动态登录界面
  • 【技术追踪】用于 CBCT 到 CT 合成的纹理保持扩散模型(MIA-2025)
  • 车载以太网-switch
  • 网站开发技术笔记/免费b站推广入口
  • 非政府组织网站的建设/连云港百度推广总代理
  • 利用wordpress赚钱/北京seo服务商
  • 网站节日设计/天津百度推广中心
  • 免费的个人简历模板pdf/seo运营是做什么的
  • 做爰视频免费安全的网站/百度网页怎么制作