裝載ucag python裝飾器理解

Attention:为了解释得通俗易懂,所以很多概念没有描述的很准确,很多只是“意思意思”,所以大家重在意会哈。如果各位知友有更好的解释和讲解的方法,还请在评论区不吝赐教。

学习python有一段时间了,对于装饰器的理解又多了一些,现在我重新再写一次对于装饰器的理解。

在讲之前我需要先铺垫一下基础知识,如果你已经掌握了就请跳过。

--------------------------------------基础知识分割线-----------------------------------------------------

1、万物皆对象。

在python中,不管什么东西都是对象。对象是什么东西呢?

对象就是你可以用来随意使用的模型。当你需要的时候就拿一个,不需要就让它放在那,垃圾回收机制会自动将你抛弃掉的对象回收。

可能对这个理解有一点云里雾里的感觉,甚至还觉得对这个概念很陌生。其实如果你都学到装饰器这里了,你已经使用过不少对象啦。

比如,我写了一个函数:

defcal(x,y):result=x+yreturnresult

这时,你可以说,你创造了一个叫做cal的函数对象。

然后,你这样使用了它:

cal(1,2)

或者,你这样使用了它:

calculate = calcalculate(1,2)

在第一种方式下,你直接使用了cal这个函数对象;

在第二种方式下,你把一个名为calculate的变量指向了cal这个函数对象。如果各位对类的使用很熟悉的话,可以把这个过程看作“实例化”。

也就是说,对象,就像是一个模子,当你需要的时候,就用它倒一个模型出来,每一个模型可以有自己不同的名字。在上面的例子中,calculate是一个模型,而你写的cal函数就是一个模子。

2、请理解函数带括号和不带括号时分别代表什么意思。

在上一个例子中,如果你只是写一个cal(也就是没有括号),那么此时的cal仅仅是代表一个函数对象;当你这样写cal(1, 2)时,就是在告诉编译器“执行cal这个函数”。

3、请确保能够理解带星号的参数是什么意思。

这个属于函数基础,要是你还没有听说过,那么就该回去好好复习一下了。具体讲解我就略过了。

----------------------------------------------正文分割线---------------------------------------------------

1、装饰器是什么?

装饰器,顾名思义,就是用来“装饰”的。

它长这个样:

@xxx

其中"xxx"是你的装饰器的名字。

它能装饰的东西有:函数、类

2、为什么我需要装饰器?

有一句名言说的好(其实是我自己说的):

“每一个轮子都有自己的用处”

所以,每一个装饰器也有自己的用处。

装饰器主要用来“偷懒”(轮子亦是如此)。

比如:

你写了很多个简单的函数,你想知道在运行的时候是哪些函数在执行,并且你又觉得这个没有必要写测试,只是想要很简单的在执行完毕之前给它打印上一句“Start”,那该怎么办呢?你可以这样:

def func_name(arg):    print 'Start func_name'    sentences

这样做没有错,but, 你想过没有,难道你真的就想给每一个函数后面都加上那么一句吗?等你都运行一遍确定没有问题了,再回来一个一个的删掉print不觉得麻烦吗?什么?你觉得写一个还是不麻烦的,那你有十个需要添加的函数呢?二十个?三十个?(请自行将次数加到超过你的忍耐阈值)……

如果你知道了装饰器,情况就开始渐渐变得好一些了,你知道可以这样写了:

deflog(func):defwrapper(*arg,**kw):print'Start %s'%funcreturnfunc(*arg,**kw)returnwrapper@logdeffunc_a(arg):pass@logdeffunc_b(arg):pass@logdeffunc_c(arg):pass

其中,log函数是装饰器。

把装饰器写好了之后,只需要把需要装饰的函数前面都加上@log就可以了。在这个例子中,我们一次性就给三个函数加上了print语句。

可以看出,装饰器在这里为我们节省了代码量,并且在你的函数不需要装饰的时候直接把@log去掉就可以了,只需要用编辑器全局查找然后删除即可,快捷又方便,不需要自己手工的去寻找和删除print的语句在哪一行。

-----------------------------------------------重点分割线--------------------------------------------------

3、装饰器原理

在上一段中,或许你已经注意到了"log函数是装饰器"这句话。没错,装饰器是函数。

接下来,我将带大家探索一下,装饰器是怎么被造出来的,来直观的感受一下装饰器的原理。

先回到刚才的那个添加'Start'问题。

假设你此时还不知道装饰器。

将会以Solution的方式呈现。

S1 我有比在函数中直接添加print语句更好的解决方案!

于是你这样做了:

defa():passdefb():passdefc():passdefmain():print'Start a'a()print'Start b'b()print'Start c'c()

感觉这样做好像没什么错,并且还避免了修改原来的函数,如果要手工删改print语句的话也更方便了。嗯,有点进步了,很不错。

S2 我觉得刚刚那个代码太丑了,还可以再优化一下!

于是你这样写了:

defa():passdefb():passdefc():passdefdecorator(func):print'Start %s'%funcfunc()defmain():decorator(a)decorator(b)decorator(c)

你现在写了一个函数来代替你为每一个函数写上print语句,好像又节省了不少时间。你欣喜的喝了一口coffee,对自己又一次做出了进步感到很满意。

嗯,确实是这样。

于是你选择出去上了个厕所,把刚刚憋的尿全部都排空(或许还有你敲代码时喝的coffee)。

回来之后,顿时感觉神清气爽!你定了定神,看了看自己刚才的“成果”,似乎又感到有一些不满意了。

因为你想到了会出现这样的情况:

def main():    decorator(a)    m = decorator(b)    n = decorator(c) + m    for i in decorator(d):        i = i + n    ......

来,就说你看到满篇的decorator你晕不晕!大声说出来!

S3 你又想了一个更好的办法。

于是你这样写了:

defa():passdefb():passdefc():passdefdecorator(func):print'Start %s'%funcreturnfunca=decorator(a)b=decorator(b)c=decorator(c)defmain():a()b()c()

这下总算是把名字给弄回来了,这样就不会晕了。你的嘴角又一次露出了欣慰的笑容(内心OS:哈哈哈,爷果然很6!)。于是你的手习惯性的端起在桌上的coffee,满意的抿了一口。

coffee的香味萦绕在唇齿之间,你满意的看着屏幕上的代码,突然!脑中仿佛划过一道闪电!要是a、b、c 三个函数带参数我该怎么办?!

你放下coffee,手托着下巴开始思考了起来,眉头紧锁。

像这样写肯定不行:

a = decorator(a(arg))

此时的本应该在decorator中做为一个参数对象的a加上了括号,也就是说,a在括号中被执行了!你只是想要a以函数对象的形式存在,乖乖的跑到decorator中当参数就好了。执行它并不是你的本意。

那该怎么办呢?

你扶了扶眼镜,嘴里开始念念有词“万物皆对象,万物皆对象……”

你的额头上开始渐渐的渗出汗珠。

突然,你的身后的背景暗了下来,一道光反射在眼镜上!不自觉的说了句

“真相はひとつだけ”!

S4 你飞速的写下如下代码。

defa(arg):passdefb(arg):passdefc(arg):passdefdecorator(func):defwrapper(*arg,**kw)print'Start %s'%funcreturnfunc(*arg,**kw)returnwrappera=decorator(a)b=decorator(b)c=decorator(c)defmain():a(arg)b(arg)c(arg)

decorator函数返回的是wrapper, wrapper是一个函数对象。而a = decorator(a)就相当于是把 a 指向了 wrapper, 由于wrapper可以有参数,于是变量 a 也可以有参数了!

终于!你从焦灼中解脱了出来!

不过, 有了前几次的经验,你这一次没有笑。

你又仔细想了想,能不能将a = decorator(a)这个过程给自动化呢?

于是你的手又开始在键盘上飞快的敲打,一会儿过后,你终于完成了你的“作品”。

你在python中添加了一个语法规则,取名为“@”,曰之“装饰器”。

你此时感觉有些累了, 起身打开门, 慢步走出去,深吸一口气,感觉阳光格外新鲜。

你的脸上终于露出了一个大大的笑容。

-------------------------------乱侃结束分割线------------------------------------------------------------

讲到这里,我想大家应该差不多都明白了装饰器的原理。

在评论中有知友问到,要是我的装饰器中也有参数该怎么办呢?

要是看懂了刚才添加参数的解决方案,也就不觉得难了。

再加一层就解决了。

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

推荐阅读更多精彩内容

  • 装饰是为函数和类指定管理代码的一种方式.装饰器本身的形式是处理其他的可调用对象的可调用的对象。 函数装饰器在函数定...
    低吟浅唱1990阅读 222评论 0 0
  • 本文为《爬着学Python》系列第四篇文章。从本篇开始,本专栏在顺序更新的基础上,会有不规则的更新。 在Pytho...
    SyPy阅读 2,489评论 4 11
  • 《战狼2》依然热血沸腾!
    浮尘过隙阅读 71评论 0 0
  • 飘雪,是冬天的一种美丽。雪花片片随风舞,寒枝点点梅花香。纷纷扬漫天皆白,飘飘然行人匆匆。风捲门檐扰残梦,雪落窗台落...
    青悬_阅读 660评论 4 13
  • RandomAccessFile 随机读取文件内容 构造方法 RandomAccessiFile raf=new ...
    HAHAYA阅读 486评论 0 0