Python 装饰器的学习笔记

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

在使用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的分享

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容