@staticmethod
:将一个方法转换为静态方法,可以在不创建类实例的情况下调用。@classmethod
:将一个方法转换为类方法,可以在不创建类实例的情况下调用,并且可以访问类的属性和方法。@property
:将一个方法转换为属性,可以像访问属性一样访问方法,而不需要使用括号调用。@abstractmethod
:定义一个抽象方法,子类必须实现该方法才能被实例化。@wraps
:将一个函数的元信息(如函数名、文档字符串、参数列表等)复制到另一个函数中,可以避免装饰器对函数元信息的影响。@lru_cache
:使用 LRU 算法实现的缓存装饰器,可以缓存函数的计算结果,避免重复计算。@timeout
:设置函数的最大执行时间,如果函数执行时间超过设定的时间,就会抛出TimeoutError
异常。@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
比较
classmethod
和 staticmethod
都是 Python 中的装饰器,用于定义类方法和静态方法。虽然它们都可以在类中定义方法,通过类名直接调用,而不需要创建类的实例,但是它们有一些不同之处。
不同点:
classmethod
的第一个参数是类本身,通常命名为cls
,而staticmethod
没有特殊的参数。classmethod
可以访问和修改类的属性和方法,而staticmethod
只能访问类的属性和方法,不能修改它们。classmethod
可以被子类继承和重写,而staticmethod
不会被继承和重写。
以下是一个简单的示例代码,演示了如何使用 classmethod
和 staticmethod
:
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
装饰器可以让我们编写更加健壮和可靠的函数,避免出现因网络故障、服务器故障或其他原因导致函数执行失败的情况。同时,它也可以提高代码的可读性和可维护性。