python教程笔记:装饰器

这是看廖老师python教程的第一个的笔记,因为这是这份教程最难的章节之一,我来来回回看了三遍,终于有所突破,写在这里是为了巩固自己的理解,同时也是希望有错的地方能够得到指正。具体内容见廖雪峰老师的课程原址

装饰器,起到增强函数的作用,同时我们不需要改动这个函数。这个部分之所以难,我觉得主要是难在对于返回函数的多次调用,容易打乱初学者的思路。接下来将分为以下三部分进行介绍:

初识装饰器

首先,装饰器要修饰的是一个函数,因此接收到函数是主体,是装饰器首要考虑的参数。以下是一个装饰器的基本模板。

#这是一个装饰器,接收一个函数func作为参数def decorator(func):        #接下来,要建一个对函数func进行处理的函数wrapper(这是装饰器的意义所在嘛)    #这个函数是有要求的:1.接收所要处理函数func的参数(以wrapper参数接收)。2.函数func的返    #回值,需要通过wrapper的返回值传回    def wrapper(*args, **kw):                {一系列函数调用前的操作}                r = func(*args, **kw)      #r保存了返回值                {一系列函数调用后的操作}                return r    return wrapper

尔后,这里有一个返回函数,返回函数,在调用外围函数的时候,它是不会马上执行的,需要接受到它特有的参数才行。

我们分析下课本的例子体会一下。首先,是一个简单的函数。

def now():    print("2015-3-25")

现在,我们希望在这个基础上,打印出函数的调用日志。我们来填充上面那个模板。

def decorator(func):        def wrapper(*args, **kw):                #填充,函数执行前日志        print('%s() start'%func.__name__)                r = func(*args, **kw)      #r保存了返回值                #填充,函数执行后日志        print('%s() end'%func.__name__)                return r    return wrapper

接下来调用这个函数

now = decorator(now)  #这里是一个返回函数,返回了wrappernow()         

返回值如下

image

接下来我们希望简化上面的过程,只需在now()定义的上方加上@decorator,看起来高大上,其实就是想说,now = decorator(now)。有了这个符号以后,直接调用now(),效果和上方完全一样了有木有,可以动手试一试。

@decoratordef now():    print("2015-3-25")

关于参数传递和返回值处理

由于上一个例子的now()没有参数,我们实际上并不能很好的体会装饰器内部的参数传递机制,也就是def wrapper(*args, **kw)这里的参数有什么用。接下来看下一个例子。

image

错误提示里说,wrapper不能接受参数而add函数给了两个参数,啥意思?这里明明是在给add传参那。如果看到这里犯了这样的迷糊,那对装饰器的原理还没有理解。

上一节说过,当加了@decorator之后,就相当于add = decorator(add)。所以,这个时候add已经不是add了,它其实是返回的wrapper;所以,我们在In[3]的地方看到的add函数,实际上是wrapper函数了。

<u style="box-sizing: border-box; outline: 0px; overflow-wrap: break-word;">到此,可以看得很清楚,add需要的参数,需要通过wrapper的参数来传递,它的返回值,则需要通过wrapper的返回值来返回。</u>(注:此时原add函数通过decorator(func)函数的形参func保存在外围函数中,具体原理且见返回函数那一节),做了修正,我们得到如下的运行结果。

image

到这里已经很完美了,但是,我们希望装饰器是一个通用物件,它不止是为add函数服务呀,还可以为其他各种函数打印运行日志。这个时候,便引入可变参数来替代原来的位置参数。运行如下。

image

补充关于装饰器有参数的说明

到这里其实装饰器的基本原理已经说明白了,但是这一节还有一个知识点有点捉急,如果装饰器本身也有参数(比如下文的text),就不止要操作的函数func有参数了。这里直接用课本的例子如下:

image

这里要指出,其实装饰器本质上就是一个处理函数的函数,因此核心是接收了func的那个函数(在本文就是decorator,因为它接收并处理函数),至于外围的log只是希望借助返回参数的闭包原理锁住text参数的。这一点由In[11]上的@log('execute')就可以看的很明白。log('exwcute')是啥,其实就是处理func的decorator函数呢。

技巧:不管嵌套了几层返回函数,最后@符号后面跟住的一定是处理函数的那个函数,如本文@decorator中的decorator函数,还有@log('execute'),其中log('execute')返回的返回函数,不正是decorator吗。

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

推荐阅读更多精彩内容