装饰器

装饰器是python提供的一个重要特性,使用装饰器,可以允许修改其他函数功能.

什么是装饰器

上边已经提到,装饰器可以修改其他函数的功能,使代码更简短.

为什么要使用装饰器

现在有一个函数test(x,y),作用是计算x+y

def test(x, y):
    return x + y

现在需要对test()的结果,再乘2,简单点的做法.

def test(x, y):
    return x + y

print(test(1,2) * 2)

如果实际项目中多次调用了test()函数,那么需要多个地方修改.于是就想到了另外一种方法,直接修改test()

def test(x, y):
    return (x + y) * 2

没有问题,对于简单的问题,可以这样修改,但实际项目中,test()很可能是前辈留下的屎山,最好不要取碰触.
有没有不需要修改原始函数,又能完成新增功能的方法呢? 骚年,使用装饰器吧

定义一个装饰器

先来一个简单的例子,现在有一个方法,没有参数,没有返回值,就输出一段信息,如下:

def a():
    print("hello")

现在需要在执行函数后自动补全world,利用装饰器来完成,代码如下.

def decorator(func):
    def inner_func():
        func()
        print("world")
    return inner_func

@decorator
def a():
    print("hello")

a()

来看装饰器的写法,首先定一个函数decorator(),参数名为func,是一个函数类型.
然后在这个函数内部再定义一个函数inner_func().在inner_func()中调用func(),然后再增加需要的功能,最后把inner_func当作返回值返回.
然后在被装饰函数a()上边用@+函数名来指定装饰函数,最后调用a()执行,实际执行的是装饰函数.

装饰器的本质

装饰器本质上就是一个闭包函数,下面来分解这个例子.
python中的一切都是对象,函数也是对象,那么也就可以进行赋值操作.

def inner_func():
    print("hello")
    print("world")

a = inner_func
a()

这么看起来可能不容易理解,那就再来一层

def decorator():
    def inner_func():
        print("hello")
        print("world")

    return inner_func


a = decorator()
a()

发现了么,装饰器实际的作用就是将装饰函数内部的闭包函数赋值给被装饰函数.

有参数有返回值的装饰函数

不是所有的函数均和上述例子一样简单,实际使用过程中会有参数,返回值.
这种情况下,就要遵循一下规则

  1. 被装饰函数有参数,装饰函数内部的闭包函数也需要有参数,并且顺序数量与被装饰函数一致
  2. 被装饰函数有返回值,闭包函数也需要有返回值,但返回值类型不限.

回到最开始的例子,用装饰器来改写一下.

def dec(func):
    def wrap(x, y):
        return func(x, y) * 2
    return wrap

@dec
def test(x, y):
    return x + y

print(test(1, 2))

wrap()参数与test()保持一致,并且有return

执行时机

了解了上述,那么装饰器是什么时机执行的,顺序是什么就很重要,在上面的例子上加一点输出.

def dec(func):
    print("进入装饰函数dec()")

    def wrap(x, y):
        print("进入内部函数wrap()")
        return func(x, y) * 2

    print("返回内部函数wrap()")
    return wrap


@dec
def test(x, y):
    return x + y

此时没有调用,直接运行,输出

进入装饰函数dec()
返回内部函数wrap()

可以看到,在执行前,test()就已经被装饰器替换了.对于外部模块,装饰器模块是在何时运行的?
将上例保存成t.py文件.新建一个python文件,import上例模块

print("导入模块之前")
import t
print("导入模块")

结果

导入模块之前
进入装饰函数dec()
返回内部函数wrap()
导入模块

可以发现,在加载模块的时候,装饰器就已经发生作用了,现在来看一下执行顺序.

def dec(func):
    print("进入装饰函数dec()")

    def wrap(x, y):
        print("进入内部函数wrap()")
        return func(x, y) * 2

    print("返回内部函数wrap()")
    return wrap


@dec
def test(x, y):
    return x + y


print("准备运行test()函数")
print("test()运行结果", test(1, 2))
print("test()函数运行完毕")

结果

进入装饰函数dec()
返回内部函数wrap()
准备运行test()函数
进入内部函数wrap()
test()运行结果 6
test()函数运行完毕

在调用被修饰函数时,才会取执行修饰函数内部的闭包函数.

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

推荐阅读更多精彩内容

  • 在学习Python的过程中,我相信有很多人和我一样,对Python的装饰器一直觉得很困惑,我也是困惑了好久,并通过...
    愚灬墨阅读 458评论 1 1
  • 在学习Python的过程中,我相信有很多人和我一样,对Python的装饰器一直觉得很困惑,我也是困惑了好久,并通过...
    lijincheng阅读 5,910评论 0 5
  • 转载来自:http://blog.csdn.net/u013471155 在学习Python的过程中,我相信有很多...
    JM68阅读 575评论 3 9
  • 一、装饰器的基本使用 在不改变函数源代码的前提下,给函数添加新的功能,这时就需要用到“装饰器”。 0.开放封闭原则...
    NJingZYuan阅读 527评论 0 0
  • 大学即将毕业,一心想要脱离象牙塔,想要去外面的世界看看。然后就没几天的功夫,我到了距离家乡万里之遥的非洲去工作。 ...
    郭瑞杰阅读 334评论 0 0