首页 > 其他分享 >装饰器

装饰器

时间:2023-08-27 09:13:16浏览次数:22  
标签:function 函数 wrapper my 装饰 def

定义

给已有函数增加额外功能的函数。其本质上就是一个闭包函数。

特点

1. 不修改已有函数的源代码(无风险)

2. 不修改已有函数的调用方式(无风险)

3. 给已有函数增加额外的功能(只需要关注额外增加的部分)

语法

1. 定义一个装饰器

2. 在目标函数上使用装饰器

通过@装饰器名称 放在定义目标函数上一行,就完成对已有函数的装饰操作

 

示例

 1 '''
 2 定义: 给已有函数增加额外功能的函数。其本质上就是一个闭包函数。
 3 
 4 特点
 5     1. 不修改已有函数的源代码(无风险)
 6     2. 不修改已有函数的调用方式(无风险)
 7     3. 给已有函数增加额外的功能(只需要关注额外增加的部分)
 8 '''
 9 
10 
11 # 1. 定义一个装饰器,本质上就是闭包
12 def decorator(func):
13     def wrapper(*args, **kwargs):
14         print("Before function execution")
15         result = func(*args, **kwargs)
16         print("After function execution")
17         return result
18 
19     return wrapper
20 
21 
22 # 2. 使用装饰器
23 @decorator
24 def my_function():
25     print("Inside my_function")
26 
27 
28 '''
29 3. 执行被装饰方法,验证装饰器是否生效
30 输出: 
31     Before function execution
32     Inside my_function
33     After function execution
34 
35 '''
36 my_function()

这个示例中,decorator是一个装饰器函数,它接受一个函数作为参数,返回一个新的函数wrapper。wrapper函数会在被装饰的函数my_function执行前后打印一些信息。最后,通过使用@decorator语法将decorator应用到my_function上。

 

 

装饰器的流程图

装饰器本质上是闭包。只不过要求外部函数的参数必须是函数,实参是目标函数的引用。内部函数内部必须调用目标函数,内部函数形参列表要包含目标函数的形参列表,如果闭包函数有且只有一个参数,那必须是函数类型,这样定义的函数才是装饰器。。

实际执行过程如下:

1. 先按要求定义一个闭包

2. 以目标函数为参数,调用外部函数得到闭包函数即内部函数的引用

3. 调用闭包函数即内部函数。内部函数会在执行目标函数前后增加扩展功能。这个扩展功能就是对目标函数的装饰。类似于java装的AOP切面

 

使用场景

装饰器可以用于很多场景,例如记录函数执行时间、缓存函数结果、验证用户权限等。下面是几个常见的装饰器示例:

 

1. 记录函数执行时间的装饰器

 1 import time
 2 
 3 
 4 def timer(func):
 5     def wrapper(*args, **kwargs):
 6         start_time = time.time()
 7         result = func(*args, **kwargs)
 8         end_time = time.time()
 9         execution_time = end_time - start_time
10         print("Execution time: {} seconds".format(execution_time))
11         return result
12 
13     return wrapper
14 
15 
16 @timer
17 def my_function():
18     time.sleep(1)
19 
20 
21 my_function()

 2. 缓存函数结果的装饰器

 1 from functools import lru_cache
 2 
 3 
 4 @lru_cache(maxsize=None)
 5 def fibonacci(n):
 6     if n <= 1:
 7         return n
 8     else:
 9         return fibonacci(n - 1) + fibonacci(n - 2)
10 
11 
12 print(fibonacci(10))

这段代码使用了Python标准库中的functools模块中的lru_cache装饰器来优化斐波那契数列的计算。让我逐步解释这段代码的每个部分:

  1. 首先,代码导入了functools模块中的lru_cache装饰器。

  2. @lru_cache(maxsize=None)这行是一个装饰器,应用在fibonacci函数上。lru_cache是"Least Recently Used Cache"(最近最少使用缓存)的缩写,它是一种用于缓存函数调用结果的方法。maxsize=None表示缓存的大小没有限制,可以存储所有不同参数的函数调用结果。

  3. def fibonacci(n): 声明了一个名为fibonacci的函数,它接受一个整数参数n,代表斐波那契数列的索引。

  4. 在函数内部,通过递归来计算斐波那契数列的第n个数。如果n小于等于1,直接返回n作为结果。

  5. 如果n大于1,递归地调用fibonacci(n - 1)fibonacci(n - 2),然后将它们的结果相加,从而计算出第n个斐波那契数。

  6. 在函数内部的递归调用中,由于应用了lru_cache装饰器,先前计算过的结果会被缓存起来,以避免重复计算。

  7. 最后,print(fibonacci(10))调用了fibonacci函数并打印 [Cannot read properties of undefined (reading 'status')]

3. 验证用户权限的装饰器

 1 def require_permission(permission):
 2     def decorator(func):
 3         def wrapper(*args, **kwargs):
 4             # 检查用户权限
 5             if has_permission(permission):
 6             # if permission == "admin":
 7                 return func(*args, **kwargs)
 8             else:
 9                 raise PermissionError("You don't have permission to access this resource")
10 
11         return wrapper
12 
13     return decorator
14 
15 
16 @require_permission("admin")
17 def delete_user(user_id):
18     # 模拟删除用户
19     pass
20 
21 
22 def has_permission(permission):
23     print(permission)
24     return False  # 模拟没有权限
25 
26 
27 delete_user(123)

多个装饰器执行顺序

多个装饰器的执行顺序是从内到外依次应用的,即最靠近被装饰函数的装饰器首先执行,然后依次向外执行。

让我通过一个示例来详细解释这个过程。

假设有两个装饰器:decorator1decorator2,以及一个被装饰的函数 my_function。它们的定义如下:

 1 def decorator1(func):
 2     def wrapper(*args, **kwargs):
 3         print("Decorator 1: Before function call")
 4         result = func(*args, **kwargs)
 5         print("Decorator 1: After function call")
 6         return result
 7 
 8     return wrapper
 9 
10 
11 def decorator2(func):
12     def wrapper(*args, **kwargs):
13         print("Decorator 2: Before function call")
14         result = func(*args, **kwargs)
15         print("Decorator 2: After function call")
16         return result
17 
18     return wrapper
19 
20 
21 @decorator1
22 @decorator2
23 def my_function():
24     print("my_function is called")
25 
26 
27 '''
28 输出:
29     Decorator 1: Before function call
30     Decorator 2: Before function call
31     my_function is called
32     Decorator 2: After function call
33     Decorator 1: After function call
34 '''
35 my_function()

现在,让我们逐步解释代码和装饰器的执行顺序:

  1. 首先,my_function被传递给 decorator2 装饰器,相当于 decorator2(my_function)。在 decorator2 内部,它的 wrapper 函数包装了 my_function

  2. my_function 被调用时,实际上是调用了 decorator2 内部的 wrapper 函数。这将输出 "Decorator 2: Before function call",然后调用原始的 my_function

  3. decorator2wrapper 函数内部,my_function 被调用,输出 "my_function is called"。

  4. 调用完成后,decorator2wrapper 函数继续执行,输出 "Decorator 2: After function call",然后将控制权返回给 decorator1

  5. 现在,decorator1 被应用于已经被 decorator2 包装过的 my_function(即 decorator1(wrapper(my_function)))。

  6. decorator1wrapper 函数内部,输出 "Decorator 1: Before function call",然后调用已经被 decorator2decorator1 包装过的函数。

  7. 同样地,输出 "my_function is called"。

  8. 调用完成后,decorator1wrapper 函数继续执行,输出 "Decorator 1: After function call"。

综上所述,装饰器的执行顺序是从最靠近被装饰函数的装饰器开始,然后逐步向外执行。在示例中,先执行 decorator2,再执行 decorator1

调用 my_function() 会产生以下输出:

Decorator 1: Before function call
Decorator 2: Before function call
my_function is called
Decorator 2: After function call
Decorator 1: After function call

  

总结:

1. 离被装饰函数最近的装饰器先装饰

2. 然后外面的装饰器再进行装饰(此时是已经装饰的函数)

3. 总的顺序为   内 -->  外,进行层层加工、装饰

标签:function,函数,wrapper,my,装饰,def
From: https://www.cnblogs.com/allenxx/p/17659621.html

相关文章

  • 【补充】装饰类的装饰器类作为装饰器
    【一】装饰类的装饰器:装饰类的装饰器是指一个类,它接收一个类作为参数,并返回一个新的类。这个新的类通常会继承自被装饰的类,并对其进行一些拓展或修改。示例代码如下:defdecorator(cls):classNewClass(cls):def__init__(self,*args,**kwargs):......
  • 上海KTV酒店装饰电镀卡通不锈钢积木熊雕塑厂家报价
    上海KTV酒店装饰电镀卡通不锈钢积木熊雕塑厂家报价Bearbrick卡通不锈钢积木熊雕塑是一个独特的塑料玩具,它的形象是一个可爱的、独特的拟人化熊公仔,带有大肚皮。卡通不锈钢积木熊雕塑虽然是一个简单的塑料玩具,但世界上一些最大的时装公司和设计师已经采用它来展示他们最新的设计和......
  • WPF-利用装饰器实现空间的自由拖动
    在项目中经常会遇到类似如下要求的需求,创建允许自由拖动的控件,这样的需求可以使用WPF的装饰器Adorner来实现。 一、什么是装饰器?装饰器是一种特殊类型的FrameworkElement,装饰器始终呈现在被装饰元素的顶部,用于向用户提供可视化提示。装饰器可以在不改变原有控件结构的基......
  • 福建学校草坪装饰镜面不锈钢风车雕塑厂家报价
    福建学校草坪装饰镜面不锈钢风车雕塑厂家报价不锈钢风车雕塑不仅是风景,更是精神象征和图腾。正如欧洲流传的一句话:上帝创造了人,荷兰风车创造了陆地。风车象征着荷兰的民族文化,人们对天空的热爱,童话般的幸福。风车在西班牙随处可见。风车虽然失去了原有的功效,但却象征着西班牙农业的......
  • 装饰电镀添加剂行业市场调研及发展趋势报告2023-2029
    2023-2029全球装饰电镀添加剂行业调研及趋势分析报告2022年全球装饰电镀添加剂市场规模约亿元,2018-2022年年复合增长率CAGR约为%,预计未来将持续保持平稳增长的态势,到2029年市场规模将接近亿元,未来六年CAGR为%。从核心市场看,中国装饰电镀添加剂市场占据全球约%的市场份额,为全......
  • python @property装饰器实现原理
    @property装饰器可以使一个对象的方法变成属性访问,比较方便,那么它是如何实现的呢?下面是一个自己动手实现的例子:classMyProperty:def__init__(self,fget=None,fset=None):self.fget=fgetself.fset=fsetdef__get__(self,instance,o......
  • python增加一个循环运行的装饰器
    在平时编程时,经常会遇到循环运行一个函数的情况,我们可以编写一个装饰器来简化这个过程,实现代码如下:defLoopRun(duration:float=60,interval:float=1,remainder:float=3)->callable:'''支持长期运行的装饰器函数duration:持续时长,单位秒interval:......
  • 高效利用Python装饰器优化函数功能与性能
    在后端开发领域,Python作为一门广泛应用的编程语言,为开发人员提供了丰富的工具和库。本文将深入探讨Python装饰器的原理、用法以及如何利用装饰器优化函数的功能和性能。通过结合实际示例,为读者提供关于装饰器的深奥知识和实用代码。1.装饰器概述与原理装饰器是Python中一种强大的......
  • 贵州售楼部小区装饰镜面钛金不锈钢鱼雕塑厂家报价
    贵州售楼部小区装饰镜面钛金不锈钢鱼雕塑厂家报价镜面钛金不锈钢鱼雕塑制作流程:不锈钢板拿到模具上实打实地去敲,而是根据石膏模型每个部分不同的形状把料下出,依照其起伏变化,进行有意识地敲打,该弯的地方敲弯,该棱的地方敲棱,可在任何有形的结实的物体上进行敲打,然后把敲好的不锈钢板......
  • Python学习 -- 高阶、闭包、回调、偏函数与装饰器探究
    Python函数作为编程的核心,涵盖了众多令人兴奋的概念,如高阶函数、闭包、回调、偏函数和装饰器。本篇博客将深入研究这些概念,结合实际案例为你解析函数的精妙,以及如何巧妙地运用它们来构建更强大、灵活的程序。高阶函数:进一步探索在上文基础上,再次回顾高阶函数,展示它们如何将函数作为......