加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

Python笔记:装饰器

发布时间:2020-12-20 10:07:20 所属栏目:Python 来源:网络整理
导读:装饰器 1、特点: 装饰器的作用就是为已存在的对象添加额外的功能,特点在于不用改变原先的代码即可扩展功能。 2、使用: 装饰器其实也是一个函数,加上@符号后放在另一个函数“头上”就实现了装饰的功能,执行被装饰的函数时,其实相当于func(*args,**kwarg

装饰器

  1、特点:装饰器的作用就是为已存在的对象添加额外的功能,特点在于不用改变原先的代码即可扩展功能。

  2、使用:装饰器其实也是一个函数,加上@符号后放在另一个函数“头上”就实现了装饰的功能,执行被装饰的函数时,其实相当于func(*args,**kwargs) = decorator(func)(*args,**kwargs)。

  3、应用场景:常用的有以下一些场景:

    • 附加功能。
    • 请求拦截:比如登录验证、权限验证等。
    • 修改返回值。
    • 函数注册。

  4、普通装饰器的基本原理:在加载装饰器时,也就是加载到@符时,会运行一次装饰器(也就是被@后的函数),它的返回值会替代被装饰的函数地址,而被装饰的函数的地址以装饰器函数参数的形式传进了装饰器。如下示例中:加载到@decorator时,运行了一次decorator()函数,这时函数hello()把函数名(也就是函数地址hello)作为装饰器参数func传了进去,decorator()执行完后返回函数inner()的函数地址,这个函数地址替代了函数hello()的函数地址,当执行hello('Jom')时,就会执行替换后的函数,即inner('Jom'),然后就会去执行inner()函数内的内容。

普通装饰器示例:

 1 def decorator(func):
 2     print('hello python!')  # 相当于给hello添加的额外功能
 3      inner(name):
 4         hello,my friend 5         func(name)  func即为hello()函数
 6 
 7     return inner
 8 
 9 @decorator  装饰器用@表示,函数decorator()装饰函数hello()
10  hello(name):
11     hello %s!' % name)
12     
13 hello(Jom')  执行函数
14 
15 # 输出--------------------------------------------------------------
16 # hello python!
17 # hello,my friend
18 # hello Jom!

?

  5、装饰器传参:此时定义装饰器时,需要在普通装饰器的外面再定义一个函数,而最外面的这个函数的参数就对应于装饰器使用时传入的参数,具体见示例。

装饰器传参示例:

 decorator_var(var1,var2):
decorator_var')
 3 
 4      装饰器的传参,就是在简单装饰器外面再套一层“壳子”
 5      并且加载到装饰器的时候,会自动执行decorator_var和decorator两个函数
 6      7         decorator 9         10             print(var1,var2)
11             func(name)
12 
13         15      decorator
16 
17 
18 @decorator_var(Python',3619 20     21 
22 
23 hello(24 
25  输出--------------------------------------------------
26  decorator_var
27  decorator
28  Python 36
29  hello Jom!

?

  6、安全防护:被装饰的函数的一些元信息,比如__name__属性,会被修改为装饰器函数返回的函数名(虽然本质上已经不是在执行原函数了,因为它被装饰了,但是“表面上”我们代码还是执行的是这个函数,所以看起来就是原先的函数的属性被修改了,这样“看起来”就是不安全的),但是为了防止这种不安全的行为,可以使用“from functools import wraps”来装饰器装饰器返回的函数,此装饰器会将原函数的一些元信息(如__module__、__name__、__doc__等)拷贝至返回的内函数中。

from functools import wraps
 2 
 4  装饰器__name__属性防护
 5  6     @wraps(func)   这个装饰器可以防止被装饰的函数的__name__属性值被修改
def inner(*args,**kwargs):   可以使用*args和**kwargs为“万能”的传参方式,当然这里也可以写成inner(a,b)
 8         func(*args,**kwargs)
 9 
10     11 
13  加载到这个装饰器时,相当于:test_func = decorator(test_func),即test_func = inner
14  如果没有对__name__的保护,加载装饰器后,如:函数test_func的__name__属性就会由“test_func”变为“inner”了
@decorator
 test_func(a,b):
17     sum of a+b: %s' % (a + b))

?

  7、多个装饰器的执行顺序:如果某个函数使用了多个装饰器,那么执行的顺序相对于原函数的位置按照从下到上(从近到远),然后再从上到下(从远到近)的顺序执行,具体见示例。

 decorator1(func):
    decorator1...)

    kwargs):
        decorator1 inner...)
        func()
     inner


 decorator2(func):
    decorator2...decorator2 inner... decorator3(func):
    decorator3...decorator3 inner... 多个装饰器,对于装饰器函数中、内函数外的部分按照从下到上的顺序执行,
# 对于内函数中的部分则按照从上到下的顺序执行。
@decorator3
@decorator2
@decorator1
 test_func():
    test_func...)


if __name__ == __main__:
    test_func()

 输出-------------------------------- decorator1... decorator2... decorator3... decorator3 inner... decorator2 inner... decorator1 inner... test_func...

?

  8、类装饰器:如果想要把一个装饰器定义为一个类,其实原理都是一样的,将装饰器当成一个可调用的对象即可,第一次加载到@Decorator时,会执行Decorator(func)语句,而执行原函数时,就是相当于执行Decorator(func)(*args,**kwargs),具体见示例。

普通类装饰器:

class Decorator:
    def __init__(self,func):
        __init__...)
        self._func = func

    __call__(self,*args,1)">__call__...)
        self._func(*args,1)">kwargs)


@Decorator
 输出------------------------ __init__... __call__... test_func...

类装饰器传参示例:

 None
        )
        (string)

     decorator_func(self):
        decorator_func...)
        self._func()

     args[0]
         self.decorator_func


@Decorator(hello hello decorator_func... test_func...

?

总结:由上面的示例其实可以看出,在定义装饰器时,无论是定义为函数的形式还是类的形式,使用时只需要简单记为decorator(func)(*args,**kwargs)就可以了,如果需要给装饰器传参,不过是在前面多了一个执行步骤而已,就变为了decorator(*dec_args,**dec_kwargs)(func)(*args,**kwargs),dec_args和dec_kwargs是给装饰器传入的参数。

?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读