Python常见装饰器使用(实用向)

2023-05-16

目录

    • 1.`@staticmethod`
    • 2.`@classmethod`
    • 3、`@classmethod` 与`@staticmethod`比较
    • 4. `@property`
    • 5.`@abstractmethod`
    • 6.`@wraps`
    • 7.`@lru_cache`
    • 8.`@timeout`
    • 9.`@retry`

  1. @staticmethod:将一个方法转换为静态方法,可以在不创建类实例的情况下调用。
  2. @classmethod:将一个方法转换为类方法,可以在不创建类实例的情况下调用,并且可以访问类的属性和方法。
  3. @property:将一个方法转换为属性,可以像访问属性一样访问方法,而不需要使用括号调用。
  4. @abstractmethod:定义一个抽象方法,子类必须实现该方法才能被实例化。
  5. @wraps:将一个函数的元信息(如函数名、文档字符串、参数列表等)复制到另一个函数中,可以避免装饰器对函数元信息的影响。
  6. @lru_cache:使用 LRU 算法实现的缓存装饰器,可以缓存函数的计算结果,避免重复计算。
  7. @timeout:设置函数的最大执行时间,如果函数执行时间超过设定的时间,就会抛出 TimeoutError 异常。
  8. @retry:在函数执行失败时自动重试,可以设置重试次数、重试间隔等参数。

这些装饰器都是 Python 中常用的装饰器,可以帮助我们简化代码、提高效率、增强程序的可读性和可维护性。

1.@staticmethod

class MyClass:
    @staticmethod
    def my_static_method(x, y):
        return x + y

# 不需要创建类实例,直接调用静态方法
result = MyClass.my_static_method(1, 2)
print(result)  # 输出 3

2.@classmethod

class MyClass:
    class_var = 0

    @classmethod
    def my_class_method(cls, x):
        cls.class_var += x
        return cls.class_var

# 不需要创建类实例,直接调用类方法
result1 = MyClass.my_class_method(1)
result2 = MyClass.my_class_method(2)
print(result1, result2)  # 输出 1 3

3、@classmethod@staticmethod比较

classmethodstaticmethod 都是 Python 中的装饰器,用于定义类方法和静态方法。虽然它们都可以在类中定义方法,通过类名直接调用,而不需要创建类的实例,但是它们有一些不同之处。

不同点:

  1. classmethod 的第一个参数是类本身,通常命名为 cls,而 staticmethod 没有特殊的参数。
  2. classmethod 可以访问和修改类的属性和方法,而 staticmethod 只能访问类的属性和方法,不能修改它们。
  3. classmethod 可以被子类继承和重写,而 staticmethod 不会被继承和重写。

以下是一个简单的示例代码,演示了如何使用 classmethodstaticmethod

class MyClass:
    class_variable = 0

    def __init__(self, instance_variable):
        self.instance_variable = instance_variable

    @classmethod
    def class_method(cls):
        cls.class_variable += 1
        print("Class variable:", cls.class_variable)

    @staticmethod
    def static_method():
        print("Static method")

# 调用类方法
MyClass.class_method()  # 输出 Class variable: 1

# 创建类实例
obj = MyClass(10)

# 调用静态方法
obj.static_method()  # 输出 Static method

# 调用类方法
obj.class_method()  # 输出 Class variable: 2

4. @property

将一个方法转换为属性,可以像访问属性一样访问方法,而不需要使用括号调用。

我们使用 @property 装饰器定义了一个 getter 方法 x,用于获取私有属性 _x 的值。我们使用 @x.setter 装饰器定义了一个 setter 方法 x,用于设置私有属性 _x 的值。

class MyClass:
    def __init__(self, x):
        self._x = x

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

# 访问属性 x,实际上调用的是方法 x()
obj = MyClass(1)
print(obj.x)  # 输出 1

# 修改属性 x,实际上调用的是方法 x(value)
obj.x = 2
print(obj.x)  # 输出 2

5.@abstractmethod

abstractmethod 是 Python 中的一个装饰器,用于定义抽象方法。抽象方法是一种没有实现的方法,它只是一个接口,需要在子类中实现。抽象方法通常用于定义一个类的接口,而不是具体的实现。

使用 abstractmethod 装饰器可以让我们在抽象类中定义抽象方法,强制要求子类实现这些方法。如果子类没有实现抽象方法,那么在实例化子类时会抛出 TypeError 异常。

以下是一个简单的示例代码,演示了如何使用 abstractmethod 装饰器定义抽象方法:

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius ** 2

# 创建 Rectangle 和 Circle 对象,并调用 area() 方法
rect = Rectangle(10, 20)
print("Rectangle area:", rect.area())

circle = Circle(5)
print("Circle area:", circle.area())

# 创建 Shape 对象,会抛出 TypeError 异常
shape = Shape()
# TypeError: Can't instantiate abstract class Shape with abstract methods area

6.@wraps

wraps 是 Python 中的一个装饰器,用于修饰其他装饰器,它可以帮助我们保留被修饰函数的元信息,例如函数名、文档字符串、参数列表等。如果我们不使用 wraps 装饰器,那么被修饰函数的元信息可能会丢失或被修改,导致代码可读性和可维护性下降。

使用 wraps 装饰器的主要用途是在编写装饰器时,保留被修饰函数的元信息。例如,如果我们编写一个装饰器,用于记录函数的执行时间,那么使用 wraps 装饰器可以保留被修饰函数的函数名、文档字符串、参数列表等信息,使得调试和维护代码更加方便。

以下是一个简单的示例代码,演示了如何使用 wraps 装饰器保留被修饰函数的元信息:

from functools import wraps
import time

def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.2f} seconds")
        return result
    return wrapper

@timer
def my_func():
    """This is a docstring"""
    print("Hello, world!")

my_func()
print("Function name:", my_func.__name__)
print("Docstring:", my_func.__doc__)
# (env) [hanhandi@VM-33-162-centos ~/hanhan_PythonScripts/装饰器使用]$ python other.py 
# Hello, world!
# my_func took 0.00 seconds
# Function name: my_func
# Docstring: This is a docstring

在上面的代码中,我们定义了一个名为 timer 的装饰器,用于记录函数的执行时间。我们使用 @wraps 装饰器修饰了内部的 wrapper 函数,保留了被修饰函数的元信息。然后,我们定义了一个名为 my_func 的函数,并使用 @timer 装饰器修饰它。最后,我们调用了 my_func() 函数,并输出了它的执行时间、函数名和文档字符串。

使用 wraps 装饰器可以让我们编写更加健壮和可维护的装饰器,同时也可以提高代码的可读性和可维护性。

7.@lru_cache

这个之前有讲解过,不过之前用的是cachetools:

https://blog.csdn.net/qq_42604176/article/details/130045268?spm=1001.2014.3001.5501

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# 缓存函数的计算结果,避免重复计算
result = fibonacci(10)
print(result)  # 输出 55

8.@timeout

timeout 是 Python 中的一个装饰器,用于设置函数的最大执行时间。如果函数在规定的时间内没有执行完毕,那么装饰器会抛出 TimeoutError 异常,中断函数的执行。

使用 timeout 装饰器的主要用途是在编写需要限制执行时间的函数时,保证函数不会一直执行下去,避免出现死循环或长时间阻塞的情况。例如,如果我们编写一个函数,用于从远程服务器下载文件,那么使用 timeout 装饰器可以设置最大下载时间,避免下载过程中出现网络故障或服务器故障导致程序一直阻塞。

以下是一个简单的示例代码,演示了如何使用 timeout 装饰器设置函数的最大执行时间:

import signal

class TimeoutError(Exception):
    pass

def timeout(seconds):
    def decorator(func):
        def handler(signum, frame):
            raise TimeoutError("Function timed out")

        def wrapper(*args, **kwargs):
            signal.signal(signal.SIGALRM, handler)
            signal.alarm(seconds)
            result = func(*args, **kwargs)
            signal.alarm(0)
            return result
        return wrapper
    return decorator

@timeout(5)
def my_func():
    import time
    time.sleep(10)
    print("Function finished")

try:
    my_func()
except TimeoutError as e:
    print("Function timed out:", e)

在上面的代码中,我们定义了一个名为 timeout 的装饰器,用于设置函数的最大执行时间。我们首先定义了一个名为 TimeoutError 的异常类,用于在函数超时时抛出异常。然后,我们定义了一个名为 decorator 的装饰器函数,它接受一个函数作为参数,并返回一个新的函数 wrapper。在 wrapper 函数中,我们使用 signal 模块设置了一个定时器,当函数执行时间超过规定的时间时,会抛出 TimeoutError 异常。最后,我们使用 @timeout(5) 装饰器修饰了 my_func 函数,设置了最大执行时间为 5 秒。在调用 my_func() 函数时,如果函数执行时间超过 5 秒,会抛出 TimeoutError 异常。

使用 timeout 装饰器可以让我们编写更加健壮和可靠的函数,避免出现死循环或长时间阻塞的情况。同时,它也可以提高代码的可读性和可维护性。

9.@retry

retry 是 Python 中的一个装饰器,用于在函数执行失败时自动重试。如果函数执行失败,装饰器会等待一段时间后再次执行函数,直到函数执行成功或达到最大重试次数为止。

使用 retry 装饰器的主要用途是在编写需要重试的函数时,保证函数能够在失败后自动重试,避免出现因网络故障、服务器故障或其他原因导致函数执行失败的情况。例如,如果我们编写一个函数,用于从远程服务器下载文件,那么使用 retry 装饰器可以设置最大重试次数和重试间隔时间,避免下载过程中出现网络故障或服务器故障导致程序中断。

以下是一个简单的示例代码,演示了如何使用 retry 装饰器设置函数的重试次数和间隔时间:

import time

class RetryError(Exception):
    pass

def retry(max_retries, wait_time):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(max_retries):
                try:
                    result = func(*args, **kwargs)
                    return result
                except Exception as e:
                    print(f"Function failed: {e}")
                    if i < max_retries - 1:
                        print(f"Retrying in {wait_time} seconds...")
                        time.sleep(wait_time)
            raise RetryError(f"Function failed after {max_retries} retries")
        return wrapper
    return decorator

@retry(max_retries=3, wait_time=2)
def my_func():
    import random
    if random.random() < 0.8:
        raise Exception("Random error")
    else:
        print("Function succeeded")

try:
    my_func()
except RetryError as e:
    print("Function failed:", e)

# Function failed: Random error
# Retrying in 2 seconds...
# Function failed: Random error
# Retrying in 2 seconds...
# Function failed: Random error
# Function failed: Function failed after 3 retries

在上面的代码中,我们定义了一个名为 retry 的装饰器,用于设置函数的最大重试次数和重试间隔时间。我们首先定义了一个名为 RetryError 的异常类,用于在函数重试次数达到最大值时抛出异常。然后,我们定义了一个名为 decorator 的装饰器函数,它接受一个函数作为参数,并返回一个新的函数 wrapper。在 wrapper 函数中,我们使用 for 循环和 try/except 语句实现了函数的重试逻辑。如果函数执行失败,会等待一段时间后再次执行函数,直到函数执行成功或达到最大重试次数为止。最后,我们使用 @retry(max_retries=3, wait_time=2) 装饰器修饰了 my_func 函数,设置了最大重试次数为 3 次,重试间隔时间为 2 秒。在调用 my_func() 函数时,如果函数执行失败,会自动重试,直到函数执行成功或达到最大重试次数为止。

使用 retry 装饰器可以让我们编写更加健壮和可靠的函数,避免出现因网络故障、服务器故障或其他原因导致函数执行失败的情况。同时,它也可以提高代码的可读性和可维护性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python常见装饰器使用(实用向) 的相关文章

随机推荐

  • C++使用rapidjson进行类的序列化与反序列化

    目录 序列化 amp 反序列化单个对象序列化反序列化使用示例 序列化 amp 反序列化对象列表 C 43 43 中可以使用第三方库来实现将类序列化成JSON文件 xff0c 以及读取JSON文件内容反序列化为类对象 这里使用rapidJso
  • c++用vector实现定长队列

    目录 queue实现vector实现 我们可以用queue或vector实现定长队列 xff0c 但是如果我们有遍历定长队列的需求的话 xff0c 使用queue不是一个好的选择 xff0c 因为queue本身不支持直接访问元素 queue
  • c++判断文件是否存在

    可以使用C 43 43 的文件流来判断文件是否存在 以下是一个简单的函数 xff0c 可以通过文件名判断文件是否存在 xff1a span class token macro property span class token direct
  • 相机内外参数的意义

    1 内参数 xff1a 由于相机坐标系使用的是毫米制的单位 xff0c 而图像平面使用的像素为单位 内参数的作用就是在这两个坐标系之间进行线性的变化 相机光轴中心Z轴方向与像平面交点称为投影中心 xff0c 其坐标为 xff0c 其单位为像
  • C++实现读写分离的双缓冲buffer

    目录 1 双缓冲区 读写分离2 后台线程定时更新数据3 类设计完整代码cache cppcache hmain cppmakefile 读写分离的双缓冲buffer有以下好处 xff1a 提高了并发读写的效率 xff1a 在多线程环境下 x
  • 返回引用与返回值与返回std::move(obj)

    返回引用与返回值相比 返回引用与返回值相比有以下几个好处 xff1a 减少内存开销 xff1a 返回值需要在函数内部创建一个临时对象 xff0c 然后将该对象的副本返回给调用者 这个过程需要分配内存 复制数据等操作 xff0c 会增加内存开
  • error: non-member function ‘XXX::IsValid(const T&)’ cannot have cv-qualifier

    这个错误提示表明你定义的函数 IsValid 是一个非成员函数 xff0c 并且带有 const 限定符 在 C 43 43 中 xff0c 非成员函数不能带有 const 限定符 xff0c 因为它们没有隐式的 this 指针 xff0c
  • c++使用regex报错regex_error

    原本写了个同时识别IPv4和IPv6地址的C 43 43 函数 xff1a span class token macro property span class token directive hash span span class to
  • c++实现日志类(写入logfile)

    span class token macro property span class token directive hash span span class token directive keyword include span spa
  • c++中以类对象作为key用于unordered_map、map,以及std::tie技巧使用

    我有一个类 span class token keyword class span span class token class name UserRegion span span class token punctuation span
  • std::set_difference用法

    std set difference 是 C 43 43 STL 中的一个算法 xff0c 用于计算两个有序范围之间的差集 xff0c 并将结果存储到另一个有序范围中 std set difference 的函数签名如下 xff1a spa
  • __builtin_xxx指令学习【1】__builtin_expect

    builtin expect是GCC编译器提供的一个内置函数 xff0c 用于告诉编译器一个分支的执行概率 xff0c 以便编译器在生成机器码时进行优化 它的语法如下 xff1a span class token function buil
  • __builtin_xxx指令学习【2】__builtin_prefetch

    builtin prefetch是GCC编译器提供的一个内置函数 xff0c 用于预取数据到CPU的缓存中 xff0c 以便提高程序的执行效率 它的语法如下 xff1a builtin prefetch const void addr in
  • __builtin_xxx指令学习【3】__builtin_popcount & __builtin_popcountll

    builtin popcount是GCC和Clang编译器提供的一个内置函数 xff0c 用于计算一个整数中二进制位为1的个数 该函数的使用背景是在一些位运算和计算机视觉等领域中 xff0c 需要对二进制数据进行处理和分析 xff0c 而二
  • 当arduino遇到树莓派(usb串口)

    arduino与树莓派cm4通过usb串口连接 xff1a 问题描述 前两天尝试了很久arduino和树莓派连接 终于找到了连接的方法 xff01 可恶 这是在简书找到的过程 主要是先在树莓派端导serial包 pip install se
  • Linux的rc.local自启动服务

    Linux的rc local自启动服务 网址 xff1a http blog csdn net 21aspnet article details 6826659 Linux有自己一套完整的启动体系 xff0c 抓住了linux启动的脉络 x
  • __builtin_xxx指令学习【4】__builtin_clz&__builtin_ctz & __builtin_clzll & __builtin_ctzll

    builtin clz是GCC和Clang编译器提供的一个内置函数 xff0c 用于计算一个整数的二进制表示中 xff0c 从最高位开始连续的0的个数 该函数的使用背景是在一些位运算和计算机视觉等领域中 xff0c 需要对二进制数据进行处理
  • __builtin_xxx指令学习【5】__builtin_bswap16/32/64

    builtin bswap16 32 64是GCC和Clang编译器提供的内置函数 xff0c 用于交换一个整数的字节顺序 其中 xff0c builtin bswap16用于交换一个16位整数的字节顺序 xff0c builtin bsw
  • 【Python】@cache装饰器使用 (依赖cachetools)

    介绍 cachetools 是一个 Python 缓存库 xff0c 可以用于缓存函数的计算结果 xff0c 以提高程序的性能和响应速度 使用 cachetools 可以避免重复计算 减少网络请求 降低数据库负载等问题 xff0c 从而提高
  • Python常见装饰器使用(实用向)

    目录 1 96 64 staticmethod 96 2 96 64 classmethod 96 3 96 64 classmethod 96 与 96 64 staticmethod 96 比较4 96 64 property 96 5