gpt4 book ai didi

python 装饰器的基本使用

转载 作者:qq735679552 更新时间:2022-09-29 22:32:09 24 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章python 装饰器的基本使用由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

知识点

  • 简单的装饰器
  • 带有参数的装饰器
  • 带有自定义参数的装饰器
  • 类装饰器
  • 装饰器嵌套
  • @functools.wrap装饰器使用

基础使用

简单的装饰器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def my_decorator(func):
   def wrapper():
     print ( 'wrapper of decorator' )
     func()
   return wrapper()
 
 
def test():
   print ( 'test done.' )
 
test = my_decorator(test)
test
 
输出:
wrapper of decorator
test done.

这段代码中,变量test指向了内部函数wrapper(), 而内部函数wrapper()中又会调用原函数test(),因此最后调用test()时,就会打印'wrapper of decorator' 然后输出 'test done.' 。

这里的函数my_decorator()就是一个装饰器,它把真正需要执行的函数test()包裹在其中,并且改变了它的行为,但是原函数test()不变.

上述代码在Python中更简单、更优雅的表示:

?
1
2
3
4
5
6
7
8
9
10
11
def my_decorator(func):
   def wrapper():
     print ( 'wrapper of decorator' )
     func()
   return wrapper()
 
@my_decorator
def test():
   print ( 'test done.' )
 
test

这里的@, 我们称为语法糖,@my_decorator就相当于前面的test=my_decorator(test)语句 。

如果程序中又其他函数需要类似装饰,只需要加上@decorator就可以,提高函数的重复利用和程序可读性 。

带有参数的装饰器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def args_decorator(func):
   def wrapper( * args, * * kwargs):
     print ( 'wrapper of decorator' )
     func( * args, * * kwargs)
   return wrapper
 
@args_decorator
def identity(name, message):
   print ( 'identity done.' )
   print (name, message)
 
identity( 'changhao' , 'hello' )
 
输出:
wrapper of decorator
identity done.
changhao hello

通常情况下,会把args和*kwargs,作为装饰器内部函数wrapper()的参数。 表示接受任意数量和类型的参数 。

带有自定义参数的装饰器

定义一个参数,表示装饰器内部函数被执行的次数,可以写成这个形式:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def repeat(num):
   def my_decorator(func):
     def wrapper( * args, * * kwargs):
       for i in range (num):
         func( * args, * * kwargs)
     return wrapper
   return my_decorator
 
 
@repeat ( 3 )
def showname(message):
   print (message)
 
showname( 'changhao' )
 
输出:
changhao
changhao
changhao

类装饰器

类也可以作装饰器,类装饰器主要依赖于函数 __call__每当调用一个示例时,函数__call__()就会被执行一次.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Count:
   def __init__( self , func):
     self .func = func
     self .num_calls = 0
 
   def __call__( self , * args, * * kwargs):
     self .num_calls + = 1
     print ( 'num of calls is: {}' . format ( self .num_calls))
     return self .func( * args, * * kwargs)
 
 
@Count
def example():
   print ( 'example done.' )
 
example()
example()
 
输出:
num of calls is : 1
example done.
num of calls is : 2
example done.

这里定义了类Count,初始化时传入原函数func(),而__call__()函数表示让变量num_calls自增1,然后打印,并且调用原函数。因此我们第一次调用函数example()时,num_calls的值是1,而第一次调用时,值变成了2.

装饰器的嵌套

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import functools
def my_decorator1(func):
   @functools .wraps(func)
   def wrapper( * args, * * kwargs):
     print ( 'execute decorator1' )
     func( * args, * * kwargs)
   return wrapper
 
 
def my_decorator2(func):
   @functools .wraps(func)
   def wrapper( * args, * * kwargs):
     print ( 'execute decorator2' )
     func( * args, * * kwargs)
   return wrapper
 
 
@my_decorator1
@my_decorator2
def test2(message):
   print (message)
 
 
test2( 'changhao' )
 
输出:
execute decorator1
execute decorator2
changhao

类装饰器

类也可以作装饰器,类装饰器主要依赖于函数 __call__每当调用一个示例时,函数__call__()就会被执行一次.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Count:
   def __init__( self , func):
     self .func = func
     self .num_calls = 0
 
   def __call__( self , * args, * * kwargs):
     self .num_calls + = 1
     print ( 'num of calls is: {}' . format ( self .num_calls))
     return self .func( * args, * * kwargs)
 
 
@Count
def example():
   print ( 'example done.' )
 
example()
example()
 
输出:
num of calls is : 1
example done.
num of calls is : 2
example done.

这里定义了类Count,初始化时传入原函数func(),而__call__()函数表示让变量num_calls自增1,然后打印,并且调用原函数。因此我们第一次调用函数example()时,num_calls的值是1,而第一次调用时,值变成了2.

装饰器的嵌套

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import functools
def my_decorator1(func):
   @functools .wraps(func)
   def wrapper( * args, * * kwargs):
     print ( 'execute decorator1' )
     func( * args, * * kwargs)
   return wrapper
 
 
def my_decorator2(func):
   @functools .wraps(func)
   def wrapper( * args, * * kwargs):
     print ( 'execute decorator2' )
     func( * args, * * kwargs)
   return wrapper
 
 
@my_decorator1
@my_decorator2
def test2(message):
   print (message)
 
 
test2( 'changhao' )
 
输出:
execute decorator1
execute decorator2
changhao

@functools.wrap装饰器使用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import functools
def my_decorator(func):
   @functools .wraps(func)
   def wrapper( * args, * * kwargs):
     print ( 'wrapper of decorator' )
     func( * args, * * kwargs)
     return wrapper
 
@my_decorator
def test3(message):
   print (message)
 
test3.__name__
 
输出
test3

通常使用内置的装饰器@functools.wrap,他会保留原函数的元信息(也就是将原函数的元信息,拷贝到对应的装饰器里) 。

装饰器用法实例

身份认证

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import functools
 
def authenticate(func):
  @functools .wraps(func)
  def wrapper( * args, * * kwargs):
   request = args[ 0 ]
   if check_user_logged_in(request):
    return func( * args, * * kwargs)
     else :
    raise Exception( 'Authentication failed' )
   return wrapper
 
@authenticate
def post_comment(request):
  pass

这段代码中,定义了装饰器authenticate;而函数post_comment(),则表示发表用户对某篇文章的评论。每次调用这个函数前,都会检查用户是否处于登录状态,如果是登录状态,则允许这项操作;如果没有登录,则不允许.

日志记录

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import time
import functools
 
def log_execution_time(func):
  @functools .wraps(func)
  def wrapper( * args, * * kwargs):
   start = time.perf_counter()
   res = func( * args, * * kwargs)
   end = time.perf_counter()
   print ( '{} took {} ms' . format (func.__name__, (end - start) * 1000 ))
   return wrapper
 
@log_execution_time
def calculate_similarity(times):
  pass

这里装饰器log_execution_time记录某个函数的运行时间,并返回其执行结果。如果你想计算任何函数的执行时间,在这个函数上方加上@log_execution_time即可.

总结

所谓装饰器,其实就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改.

以上就是python 装饰器的基本使用的详细内容,更多关于python 装饰器的资料请关注我其它相关文章! 。

原文链接:https://segmentfault.com/a/1190000038959829 。

最后此篇关于python 装饰器的基本使用的文章就讲到这里了,如果你想了解更多关于python 装饰器的基本使用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com