• Python基础之装饰器


    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 ret
    		return wrapper
    
    d=Decorators()
    @d.log_func
    def fib(n):
    	if n<=1:
    		return 0
    	return fib(n-1)+fib(n-2)
    
    fib(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    使用缺点:每次使用装饰器必须创建一个对象,且self参数没有用

    1.2.2 使用类方法装饰器

    不用实例中装饰器可以使用类中装饰器,添加@classmethod变成类方法

    class Decorators:
    	@classmethod
    	def 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 ret
    		return wrapper
    
    @Decorators.log_func
    def fib(n):
    	if n<=1:
    		return 0
    	return fib(n-1)+fib(n-2)
    
    fib(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这种方式虽然不用创建对象了,直接类名调用,但是第一个参数cls依然没用到

    1.2.3 使用类中静态装饰器

    假如装饰器和对象无关,和类无关,可以使用静态装饰器@staticmethod

    class Decorators:
    	@staticmethod
    	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 ret
    		return wrapper
    
    @Decorators.log_func
    def fib(n):
    	if n<=1:
    		return 0
    	return fib(n-1)+fib(n-2)
    
    fib(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这种方式虽然不用创建对象,直接类名调用,也不会有第一个参数没用到的情况
    当把一个装饰器封装到类里面时,这个方式就不错
    注意:用@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 ret
    		return wrapper
    
    	@log_func
    	def fib(n):
    		if n<=1:
    			return 0
    		return fib(n-1)+fib(n-2)
    	
    	# 在类中或类外都可以使用装饰器添加如下方法
    	# 这句话只能放到类末尾
    	log_func=staticmethod(log_func)
    d=Decorators()
    d.fib(3)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    如上代码,就可以在类中或者类外都使用装饰器

    1.3 内部装饰器

    1.3.1 @property

    @propertyPython中的一个内置装饰器,它可以将一个方法转换为属性。具体来说,@property 装饰器可以将一个方法转换为只读属性,这意味着我们可以像访问属性一样访问这个方法,而不需要调用它。例如:

    class MyClass:
        def __init__(self, x):
            self._x = x
        @property
        def x(self):
            return self._x
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这个例子中,我们定义了一个名为 MyClass 的类,并在其中定义了一个名为 x 的方法。我们使用 @property 装饰器将该方法转换为只读属性,这样我们就可以像访问属性一样访问这个方法

    obj = MyClass(42)
    	print(obj.x)  # 输出 42
    
    • 1
    • 2

    即:带有@property装饰器的函数被调用时,后面不能加小括号()

    2 常用装饰器

    2.1 @timer:测量执行时间

    优化代码性能是非常重要的。@timer装饰器可以帮助我们跟踪特定函数的执行时间。通过用这个装饰器包装函数,我可以快速识别瓶颈并优化代码的关键部分。下面是它的工作原理:

    import time
    
    def 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 result
    	return wrapper
    @timer
    def my_data_processing_function():
    # Your data processing code here
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    将@timer与其他装饰器结合使用,可以全面地分析代码的性能。

    2.2 @memoize:缓存结果

    在数据科学中,我们经常使用计算成本很高的函数。@memoize装饰器帮助我缓存函数结果,避免了相同输入的冗余计算,显著加快工作流程:

    def memoize(func):
    	cache = {}
    	def wrapper(*args):
    		if args in cache:
    			return cache[args]
    		result = func(*args)
    		cache[args] = result
    		return result
    	return wrapper
    @memoize
    def fibonacci(n):
    	if n <= 1:
    		return n
    	return fibonacci(n - 1) + fibonacci(n - 2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在递归函数中也可以使用 @memoize来优化重复计算。

    2.3 @validate_input:数据验证

    数据完整性至关重要, @validate_input 装饰器可以验证函数参数,确保它们在继续计算之前符合特定的标准:

    def validate_input(func):
    	def wrapper(*args, **kwargs):
    		# Your data validation logic here
    		if 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    可以方便的使用@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 result
    
    		return wrapper
    @log_results
    def calculate_metrics(data):
    # Your metric calculation code here
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    @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 None
    		return wrapper
    @suppress_errors
    def preprocess_data(data):
    # Your data preprocessing code here
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    @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 result
    		else:
    			raise ValueError("Invalid output. Please check your function logic.")
    	return wrapper
    
    @validate_output
    def clean_data(data):
    # Your data cleaning code here
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这样可以始终为验证函数输出定义明确的标准。

    2.7 @retry:重试执行

    @retry装饰器帮助我在遇到异常时重试函数执行,确保更大的弹性:

    import time
    
    def retry(max_attempts, delay):
    	def decorator(func):
    		def wrapper(*args, **kwargs):
    			attempts = 0
    			while attempts < max_attempts:
    				try:
    					return func(*args, **kwargs)
    				except Exception as e:
    					print(f"Attempt {attempts + 1} failed. Retrying in {delay} seconds.")
    					attempts += 1
    					time.sleep(delay)
    			raise Exception("Max retry attempts exceeded.")
    		return wrapper
    	return decorator
    
    @retry(max_attempts=3, delay=2)
    def fetch_data_from_api(api_url):
    # Your API data fetching code here
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    使用@retry时应避免过多的重试。

    2.8 @visualize_results:漂亮的可视化

    @visualize_results装饰器数据分析中自动生成漂亮的可视化结果

    import matplotlib.pyplot as plt
    
    def visualize_results(func):
    	def wrapper(*args, **kwargs):
    		result = func(*args, **kwargs)
    		plt.figure()
    		# Your visualization code here
    		plt.show()
    		return result
    	return wrapper
    
    @visualize_results
    def analyze_and_visualize(data):
    # Your combined analysis and visualization code here
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.10 @deprecated:处理废弃的函数

    随着我们的项目更新迭代,一些函数可能会过时。@deprecated装饰器可以在一个函数不再被推荐时通知用户:

    import warnings
    
    def 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    记一次解决Pyqt6/Pyside6添加QTreeView或QTreeWidget导致窗口卡死(未响应)的新路历程,打死我都想不到是这个原因
    WinSCP连接Ubuntu拒绝访问的问题
    创建数据库脚本
    Theory behind GAN
    Flutter 从源码看Getx的依赖原理
    05 doris 集群搭建
    消防设备电源监控系统在城市建筑中的应用
    宝马遭黑客破解,客户愿为其买单
    C语言_函数指针数组的应用
    Java SpringBoot VII
  • 原文地址:https://blog.csdn.net/u012060033/article/details/132998914