EfonMark

一番码客 : 挖掘你关心的亮点。
http://www.efonmark.com

本文目录:

[TOC]

image-20200503231031637

装饰器是Python非常重要的高级特性之一。装饰器的威力在于无需修改已有代码即可为程序添加新功能。

装饰器如何使用,首先我们来看一个例子。

例子一:用装饰器实现计算一个函数的执行时间。

1
#!/usr/bin/env python
2
import time
3
def calcTime(func):
4
    def wrapper(num):
5
        startTime = time.time()
6
        func(num)
7
        endTime = time.time()
8
        interval = endTime - startTime
9
        print('Time interval:%f secs' % intarval)
10
    return wrapper
11
@calcTime
12
def timeTest(num):
13
    print('timeTest start')
14
    print('sleep %d second...' % num)
15
    time.sleep(num)
16
    print('timeTest end')
17
    
18
timeTest(1)

执行结果:

1
timeTest start
2
sleep 1 second...
3
timeTest end
4
Time interval:1.001107 secs

说明:

  • 当被装饰的函数timeTest()有参数时,可将装饰器的内嵌函数wrapper修改为被装饰函数的形式即可。此时,timeTest(1)相当于calcTime(timeTest(1))

带参数的装饰器

假设想要使用共同的装饰器来修饰多个不同的函数, 则这些不同的函数参数形式不同,装饰器可以通过可变参数 (* args, **kwargs)的方式实现内嵌函数。

那么,对于装饰器本真带参数的情况,这里举一个例子。

例子二:为装饰器添加一个bool变量,通过变量的真假判断是否调用计时器功能。

1
#!/usr/bin/env python
2
import time
3
def calcTime(flag = False):
4
    if flag:
5
        def _calcTime(func):
6
            def wrapper(num):
7
                startTime = time.time()
8
                func(num)
9
                endTime = time.time()
10
                interval = endTime - startTime
11
                print('Time interval:%f secs' % interval)
12
            return wrapper
13
    else:
14
        def _calcTime(func):
15
            return func
16
    return _calcTime
17
@calcTime(False)
18
def timeTest1():
19
    print('timeTest1 start')
20
    print('sleep 1 second...')
21
    time.sleep(1)
22
    print('timeTest1 end')
23
@calcTime(True)
24
def timeTest2(num):
25
    print('timeTest2 start')
26
    print('sleep %d second...' % num)
27
    time.sleep(num)
28
    print('timeTest2 end')
29
    
30
timeTest1()
31
print()
32
timeTest2(2)

执行结果:

1
timeTest1 start
2
sleep 1 second...
3
timeTest1 end
4
5
timeTest2 start
6
sleep 2 second...
7
timeTest2 end
8
Time interval:2.002649 secs

说明:

  • 将同一个装饰器 calcTime用于两个不同的函数:timeTest1()和timeTest2(num) , 一个没有参数, 一个有参数。
  • 通过装饰器的参数可以为装饰过程添加判断,@calcTime(True)表示进行计时,@calcTime(False)不会进行计时。

装饰器调用顺序

如果使用多个装饰器修饰同一函数时,装饰器的调用顺序怎样呢?

例子三:

1
#!usr/bin/env python
2
def dec1(func):
3
    print('dec1')
4
    def wrapper():
5
        print('dec1_wrapper')
6
        func()
7
    return wrapper
8
def dec2(func):
9
    print('dec2')
10
    def wrapper():
11
        print(dec2_wrapper)
12
        func()
13
    return wrapper
14
@dec1
15
@dec2
16
def testFunc():
17
    print('testFunc')
18
    
19
testFunc()

执行结果:

1
dec2
2
dec1
3
dec1_wrapper
4
dec2_wrapper
5
testFunc

说明:

  • 通过运行结果可以看出, 装饰器的调用顺序与语法糖@ 的声明顺序相反。
  • 以上程序中的testFunc,相当于dec1(dec2(testFunc))。
参考:
- 《物联网Python开发实战》
免费知识星球:一番码客-积累交流
微信公众号:一番码客
微信:Efon-fighting
网站:http://www.efonmark.com

蜀ICP备19039940号

总访问量为