测试不止会点点点软件测试Python专家之路颠覆你的Python实践

Python 装饰器的学习笔记

2019-04-03  本文已影响0人  我爱泡澡堂

一、作为一个测试为什么学装饰器?

在使用python写东西的时候,可能会遇到并使用到装饰器,为了加深“功力”还是很有必要去学习一下的。不能只知道使用,完全去“复制”别人的代码,还是要知道为什么要这么写的。以后可能亲自去实现一个装饰器的机会并不多,所以也许并不需要能熟练的去写一个装饰器。为了满足“好奇心”了解一下还是很有不错的学习过程。

二、什么是装饰器

装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。

这是我查阅资料时,看到比较多的描述,所以装饰器它是:

  1. 它也是一个函数
  2. 能够给修饰的代码提供额外的功能

这让我想到了java中的“注解”,当然也许他们的实现方式不同。(若类比失当,大佬勿喷,留言指正)
都类似@xxxx的语法糖写法。

三、 典型的应用场景

一般应用于抽离出与函数逻辑无关的可重用的代码,比如插入日志、性能测试、事务处理、缓存、权限验证等场景。

举个例子:

  1. 在flask框架中,来做路由的定义
from flask import Flask
 
app = Flask(__name__)
 
@app.route('/')
def hello_world():
    return 'Hello World!'
 
if __name__ == '__main__':
    app.run()
  1. 在单元测试中,可以用来忽略某些测试case
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
    def test_not_run(self):
        pass

四、最简单的一种自定义装饰器

装饰器无参数,被装饰的函数也是无参数的,是最基本的一种自定义参数。

最常被用来举例的场景:计算某个函数的运行耗时

  1. 先看下不用装饰器的写法吧
import time
def foo():
    for i in range(10):
        print('....')
        time.sleep(0.5)


start_time = time.time()
foo()
end_time = time.time()
print('spend time is {}'.format(end_time - start_time))

不多介绍了吧。
但是现在需要你再写一个函数,也是计算其的耗时,你难道还有在写一遍吗?
所以我们可以把重复的代码剥离出来,以往的做法可能是抽取公共方法,但是这种逻辑你会发现有点无从下手,重复的代码在你的逻辑前后,这个时候装饰器的作用就出来了。

import time

def show_time(func):
    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        print('spend time is {}'.format(end_time - start_time))

    return wrapper


@show_time
def foo():
    for i in range(5):
        print('*****')
        time.sleep(0.5)


@show_time
def foo_copy():
    for i in range(5):
        print('+++++')
        time.sleep(0.5)


foo()
foo_copy()

看一下打印结果感受一下:

*****
*****
*****
*****
*****
spend time is 2.5002501010894775
+++++
+++++
+++++
+++++
+++++
spend time is 2.5002498626708984

感觉有点不错。

五、被装饰函数带参数的装饰器

本例是被装饰的函数带两个参数,而装饰器函数不带参数的,有点简单,代码如下:

import time


def show_time(func):
    def wrapper(a, b):
        start_time = time.time()
        func(a, b)
        end_time = time.time()
        print('spend time is {}'.format(end_time - start_time))

    return wrapper


@show_time
def foo(a, b):
    for i in range(5):
        print('a + b = ' + str(a + b))
        time.sleep(0.5)


foo(1, 2)

打印结果:

a + b = 3
a + b = 3
a + b = 3
a + b = 3
a + b = 3
spend time is 2.5002501010894775

六、装饰器带参数的情况

就是再使用一个带参数的函数,将装饰器再做一层封装,返回一个装饰器函数。在装饰器函数中就可以使用这个传进来的参数,这种函数好像也叫做闭包函数。(才疏学浅,不做解释)

举例代码:

import time


def is_show_time(is_show=True):
    def show_time(func):
        def wrapper(a, b):
            start_time = time.time()
            func(a, b)
            end_time = time.time()
            if is_show is True:
                print('spend time is {}'.format(end_time - start_time))

        return wrapper

    return show_time


@is_show_time(is_show=True)
def foo(a, b):
    for i in range(5):
        print('a + b = ' + str(a + b))
        time.sleep(0.5)


@is_show_time(is_show=False)
def foo_copy(a, b):
    for i in range(5):
        print('a + b = ' + str(a + b))
        time.sleep(0.5)


foo(1, 2)
foo_copy(3, 4)

is_show_time函数将我们上面例子中的show_time函数做了封装,透出一个参数用来控制是否执行打印语句。
foofoo_copy分别传入两种参数值来测试一下是否符合预期。
打印结果如下:

a + b = 3
a + b = 3
a + b = 3
a + b = 3
a + b = 3
spend time is 2.5
a + b = 7
a + b = 7
a + b = 7
a + b = 7
a + b = 7

Process finished with exit code 0

七、后记

介绍上面这些,应该对装饰器有一个大概的了解,想要更深的去了解,可以多利用搜索引擎。

感谢:whyaza的分享

上一篇下一篇

猜你喜欢

热点阅读