python 修饰符**kwag_裝載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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值