Python基础之装饰器
文章目录
- 1 装饰器
- 1.1 定义
- 1.2 使用示例
- 1.2.1 使用类中实例装饰器
- 1.2.2 使用类方法装饰器
- 1.2.3 使用类中静态装饰器
- 1.2.4 使用类中普通装饰器
- 1.3 内部装饰器
- 1.3.1 @property
- 2 常用装饰器
- 2.1 @timer:测量执行时间
- 2.2 @memoize:缓存结果
- 2.3 @validate_input:数据验证
- 2.4 @log_results:日志输出
- 2.5 @suppress_errors:优雅的错误处理
- 2.6 @validate_output:确保质量结果
- 2.7 @retry:重试执行
- 2.8 @visualize_results:漂亮的可视化
- 2.9 @debug:调试变得更容易
- 2.10 @deprecated:处理废弃的函数
1 装饰器
装饰器(Decorators
)是Python
中一种强大而灵活的功能,用于修改或增强函数或类的行为。
1.1 定义
装饰器本质上是一个函数,它接受另一个函数或类
作为参数,并返回一个新的函数或类
。它们通常用于在不修改原始代码的情况下添加额外的功能或功能
装饰器函数是一种Python
语言中的特殊函数,它可以用来修改其他函数的行为。装饰器函数通常接受一个函数
作为参数,并返回一个新的函数
,这个新函数通常会在原函数的基础上添加一些额外的功能
作用
:为函数增加新功能,减少重复性操作,使代码简洁
1.2 使用示例
使用装饰器的步骤:
- 定义装饰器
- 通过
@
调用装饰器
1.2.1 使用类中实例装饰器
装饰器一般是放在全局命名空间或单独一个类里,但是把装饰器放到类里面,相当于把一个函数变成类的方法
class Decorators:def log_func(self,func):def wrapper(*args,**kwargs):print(f"function start")print(f"args:{args}")ret=func(*args,**kwargs)print(f"function end!")return retreturn wrapperd=Decorators()
@d.log_func
def fib(n):if n<=1:return 0return fib(n-1)+fib(n-2)fib(3)
使用缺点:每次使用装饰器必须创建一个对象,且self参数没有用
1.2.2 使用类方法装饰器
不用实例中装饰器可以使用类中装饰器,添加@classmethod
变成类方法
class Decorators:@classmethoddef log_func(cls,func):def wrapper(*args,**kwargs):print(f"function start")print(f"args:{args}")ret=func(*args,**kwargs)print(f"function end!")return retreturn wrapper@Decorators.log_func
def fib(n):if n<=1:return 0return fib(n-1)+fib(n-2)fib(3)
这种方式虽然不用创建对象了,直接类名调用,但是第一个参数cls依然没用到
1.2.3 使用类中静态装饰器
假如装饰器和对象无关,和类无关,可以使用静态装饰器@staticmethod
class Decorators:@staticmethoddef log_func(func):def wrapper(*args,**kwargs):print(f"function start")print(f"args:{args}")ret=func(*args,**kwargs)print(f"function end!")return retreturn wrapper@Decorators.log_func
def fib(n):if n<=1:return 0return fib(n-1)+fib(n-2)fib(3)
这种方式虽然不用创建对象,直接类名调用,也不会有第一个参数没用到的情况
当把一个装饰器封装到类里面时,这个方式就不错
注意
:用@staticmethod
修饰的装饰器不能装饰类里面的方法,会直接报错
1.2.4 使用类中普通装饰器
如果在含有装饰器的类中使用自己的装饰器时,可以把装饰器当成普通方法
class Decorators: # 此处的log_func可以理解为辅助函数或辅助装饰器def log_func(func):def wrapper(*args,**kwargs):print(f"function start")print(f"args:{args}")ret=func(*args,**kwargs)print(f"function end!")return retreturn wrapper@log_funcdef fib(n):if n<=1:return 0return fib(n-1)+fib(n-2)# 在类中或类外都可以使用装饰器添加如下方法# 这句话只能放到类末尾log_func=staticmethod(log_func)
d=Decorators()
d.fib(3)
如上代码,就可以在类中或者类外都使用装饰器
1.3 内部装饰器
1.3.1 @property
@property
是Python
中的一个内置装饰器,它可以将一个方法转换为属性。具体来说,@property
装饰器可以将一个方法转换为只读属性,这意味着我们可以像访问属性一样访问这个方法,而不需要调用它。例如:
class MyClass:def __init__(self, x):self._x = x@propertydef x(self):return self._x
在这个例子中,我们定义了一个名为 MyClass 的类,并在其中定义了一个名为 x 的方法。我们使用 @property
装饰器将该方法转换为只读属性,这样我们就可以像访问属性一样访问这个方法
obj = MyClass(42)print(obj.x) # 输出 42
即:带有@property
装饰器的函数被调用时,后面不能加小括号()
2 常用装饰器
2.1 @timer:测量执行时间
优化代码性能是非常重要的。@timer
装饰器可以帮助我们跟踪特定函数的执行时间。通过用这个装饰器包装函数,我可以快速识别瓶颈并优化代码的关键部分。下面是它的工作原理:
import timedef timer(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 to execute.")return resultreturn wrapper
@timer
def my_data_processing_function():
# Your data processing code here
将@timer与其他装饰器结合使用,可以全面地分析代码的性能。
2.2 @memoize:缓存结果
在数据科学中,我们经常使用计算成本很高的函数。@memoize
装饰器帮助我缓存函数结果,避免了相同输入的冗余计算,显著加快工作流程:
def memoize(func):cache = {}def wrapper(*args):if args in cache:return cache[args]result = func(*args)cache[args] = resultreturn resultreturn wrapper
@memoize
def fibonacci(n):if n <= 1:return nreturn fibonacci(n - 1) + fibonacci(n - 2)
在递归函数中也可以使用 @memoize
来优化重复计算。
2.3 @validate_input:数据验证
数据完整性至关重要, @validate_input 装饰器可以验证函数参数,确保它们在继续计算之前符合特定的标准:
def validate_input(func):def wrapper(*args, **kwargs):# Your data validation logic hereif valid_data:return func(*args, **kwargs)else:raise ValueError("Invalid data. Please check your inputs.")return wrapper
@validate_input
def analyze_data(data):
# Your data analysis code here
可以方便的使用@validate_input
在数据科学项目中一致地实现数据验证。
2.4 @log_results:日志输出
在运行复杂的数据分析时,跟踪每个函数的输出变得至关重要。@log_results
装饰器可以帮助我们记录函数的结果,以便于调试和监控:
def log_results(func):def wrapper(*args, **kwargs):result = func(*args, **kwargs)with open("results.log", "a") as log_file:log_file.write(f"{func.__name__} - Result: {result}\n")return resultreturn wrapper
@log_results
def calculate_metrics(data):
# Your metric calculation code here
将@log_results
与日志库结合使用,以获得更高级的日志功能。
2.5 @suppress_errors:优雅的错误处理
数据科学项目经常会遇到意想不到的错误,可能会破坏整个计算流程。@suppress_errors
装饰器可以优雅地处理异常并继续执行:
def suppress_errors(func):def wrapper(*args, **kwargs):try:return func(*args, **kwargs)except Exception as e:print(f"Error in {func.__name__}: {e}")return Nonereturn wrapper
@suppress_errors
def preprocess_data(data):
# Your data preprocessing code here
@suppress_errors
可以避免隐藏严重错误,还可以进行错误的详细输出,便于调试
2.6 @validate_output:确保质量结果
确保数据分析的质量至关重要。@validate_output
装饰器可以帮助我们验证函数的输出,确保它在进一步处理之前符合特定的标准:
def validate_output(func):def wrapper(*args, **kwargs):result = func(*args, **kwargs)if valid_output(result):return resultelse:raise ValueError("Invalid output. Please check your function logic.")return wrapper@validate_output
def clean_data(data):
# Your data cleaning code here
这样可以始终为验证函数输出定义明确的标准。
2.7 @retry:重试执行
@retry
装饰器帮助我在遇到异常时重试函数执行,确保更大的弹性:
import timedef retry(max_attempts, delay):def decorator(func):def wrapper(*args, **kwargs):attempts = 0while attempts < max_attempts:try:return func(*args, **kwargs)except Exception as e:print(f"Attempt {attempts + 1} failed. Retrying in {delay} seconds.")attempts += 1time.sleep(delay)raise Exception("Max retry attempts exceeded.")return wrapperreturn decorator@retry(max_attempts=3, delay=2)
def fetch_data_from_api(api_url):
# Your API data fetching code here
使用@retry时应避免过多的重试。
2.8 @visualize_results:漂亮的可视化
@visualize_results
装饰器数据分析中自动生成漂亮的可视化结果
import matplotlib.pyplot as pltdef visualize_results(func):def wrapper(*args, **kwargs):result = func(*args, **kwargs)plt.figure()# Your visualization code hereplt.show()return resultreturn wrapper@visualize_results
def analyze_and_visualize(data):
# Your combined analysis and visualization code here
2.9 @debug:调试变得更容易
调试复杂的代码可能非常耗时。@debug
装饰器可以打印函数的输入参数和它们的值,以便于调试:
def debug(func):def wrapper(*args, **kwargs):print(f"Debugging {func.__name__} - args: {args}, kwargs: {kwargs}")return func(*args, **kwargs)return wrapper
@debug
def complex_data_processing(data, threshold=0.5):
# Your complex data processing code here
2.10 @deprecated:处理废弃的函数
随着我们的项目更新迭代,一些函数可能会过时。@deprecated
装饰器可以在一个函数不再被推荐时通知用户:
import warningsdef deprecated(func):def wrapper(*args, **kwargs):warnings.warn(f"{func.__name__} is deprecated and will be removed in future versions.", DeprecationWarning)return func(*args, **kwargs)return wrapper
@deprecated
def old_data_processing(data):
# Your old data processing code here