python装饰器之自己的理解,欢迎更正
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python装饰器之自己的理解,欢迎更正相关的知识,希望对你有一定的参考价值。
python装饰器
装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。
闭包
两个函数嵌套,内函数使用外函数的变量,外函数的返回值是内函数的引用。
例子一:
#_*_coding:utf-8_*_ def bibao(number): print ‘bibao function start‘ def bibao_in(number2): #需要用到外函数的变量number return number + number2 #返回的是内函数的引用 return bibao_in #调用函数bibao(100)后,return回bibao_in函数的引用,test1就指向bibao_in test1 = bibao(100) #test1()调用的是bibao_in函数 print test1(200) #又创建了一个指向bibao_in的对象test2 test2 = bibao(500) print test2(200)
闭包中传递的参数是函数
例子二:
#_*_coding:utf-8_*_ def test(fn): #形参是一个函数 def test_passwd(): print ‘testing password‘ if True: #调用函数fn fn() return test_passwd def test3(): print ‘a function‘ #1.将test3指向的函数地址作为形参,传入test中(执行后fn指向test3); #2.test()函数返回结果是内函数test_passwd指向的函数体地址 #3.赋值语句,test3被重新定义,现在它指向test_passwd test3 = test(test3) #调用test3,也就调用了test_passwd,因它已与test_passwd指向同一函数体 test3()
装饰器
例子三:效果与例子二是相同的,只不过此处使用装饰器
#_*_coding:utf-8_*_
def test(fn): #形参是一个函数 def test_passwd(): print ‘进行身份验证...‘ if True: #调用函数fn fn() return test_passwd ‘‘‘使用语法糖进行装饰,作用就是更改test3指向的函数体,这可以帮助我们在不改变函数内部结构的情况下,增加它的功能(也就是对其装饰,比如对其增加一个验证功能,增加收集日志的功能)。@test与test3 = test(test3)等价‘‘‘ @test def test3(): print ‘start test3‘ #调用test3,也就调用了test_passwd,因它已与test_passwd指向同一函数体 test3() 结果: 进行身份验证... start test3
如果被装饰的函数带参数呢
例子四:
def func(fn): print ‘开始装饰‘ #使用可变参数类型,方便对多个不同参数的函数进行装饰 def func_in(*args,**kwargs): print ‘校验中‘ #fn调用了原来的test,所以一定也要有参数 fn(*args,**kwargs) return func_in #对有参数的函数进行装饰 @func def test(a,b,c): print ‘a=%d,b=%d,c=%d‘ % (a,b,c) @func def test2(a,b,c,d): print ‘a=%d,b=%d,c=%d,d=%d‘ % (a,b,c,d) #如果不带参数,装饰器也可以对其进行装饰 @func def test3(): print ‘i have nothing‘ #调用时带参数,所以test指向的func_in函数也必须有参数 test(1,2,3) test2(1,2,3,4) test3() 结果: #注意程序执行到@func语法糖时就进行装饰,不是函数被调用的时候被装饰的 开始装饰 开始装饰 开始装饰 校验中 a=1,b=2,c=3 校验中 a=1,b=2,c=3,d=4 校验中 i have nothing
被装饰的函数有返回值?
例子五:
例子五: #_*_coding:utf-8_*_ def func(fn): print ‘开始装饰‘ #使用可变长参数类型,方便对多个不同参数的函数进行装饰 def func_in(*args,**kwargs): print ‘校验中‘ #fn调用了原来的test,这里用rtn接收函数的返回值,再return rtn,这样就能保证返回原来函数的返回值 rtn = fn(*args,**kwargs) return rtn return func_in #对有参数的函数进行装饰 @func def test(a,b,c): print ‘a=%d,b=%d,c=%d‘ % (a,b,c) #对有返回值的函数进行装饰 @func def test3(): return ‘i have nothing‘ #调用时带参数,所以test指向的func_in函数也必须有参数 test(1,2,3) print test3() 结果: 开始装饰 开始装饰 校验中 a=1,b=2,c=3 校验中 i have nothing
函数被装饰多次时,装饰的顺序是怎样?
例子六:
def makeBold(fn): # 1 print ‘start Bold decorate‘ def Bold(*args,**kwargs): print ‘make words Bold‘ rtn = ‘<b>‘+ fn(*args,**kwargs) + ‘</b>‘ return rtn return Bold def makeItalian(fn): # 2 print ‘start Italian decorate‘ def Italian(*args,**kwargs): print ‘make words italian‘ rtn = ‘<i>‘ + fn(*args,**kwargs) + ‘</i>‘ return rtn return Italian @makeBold # 3 @makeItalian # 4 def words(): # 5 return ‘hello Paris‘ print words() # 6 结果:总结来说,python是从内到外进行装饰 start Italian decorate start Bold decorate make words Bold make words italian <b><i>hello Paris</i></b>
详细解释一下:
# 1 程序创造一个内存空间, makeBold指向这片地址 # 2 程序创造一个内存空间, makeItalian 指向这片地址
# 3 @makeBold要对下面的函数进行装饰,但发现下面不是函数,而是装饰器,那它就等待下面装饰器装饰完成
# 4 @makeItalian进行装饰,words= makeItalian(words):打印‘start Italian decorate‘:
fn就指向了words指向的函数体,words指向了makeItalian函数的返回值,也就是Italian函数体。
# 5 @makeItalian装饰完后,@makeBold对其装饰,即words= makeBold(words);打印‘start Bold decorate‘ fn就指向了Italian,words就指向makeBold返回值,也就是Bold函数
# 6 调用words()后,执行Bold(),打印‘make words Bold‘ 执行到fn()时进入Italian(),打印‘make words italian‘ 执行到fn()时进入FFFF(),返回hello Paris(FFFF完成); 返回<i>hello Paris</i>,(Italian完成); 返回<b><i>hello Paris</i></b>,(Bold完成)
装饰器可以如函数调用一样“堆叠“起来,这里有一个更加普遍的例子,使用了多个装饰器:
@deco2 @deco1 def func(arg1, arg2, ...): pass #这和创建一个组合函数是等价的。 def func(arg1, arg2, ...): pass func = deco2(deco1(func)) #函数组合用数学来定义就像这样: (g · f)(x) = g(f(x))。对于在python中的一致性: @g @f def foo(): pass #与 foo=g(f(foo))相同
带参数的装饰器 例子六:
#接收一个参数a def with_arg(a): def bibao(fn): print ‘start decorate‘ #被装饰的函数带参数 def bibao_in(*arg,**kwarg): print ‘i am ‘+a #被装饰的参数带返回值 rtn = fn(*arg,**kwarg) return rtn #返回bibao_in指向的函数体 return bibao_in #返回bibao指向的函数体 return bibao #装饰器带参数时,先将这个参数传入with_arg()函数中,其返回函数bibao,再使用bibao对test1进行装饰 @with_arg(‘first‘) def test1(a,b): print ‘i am test1‘ return ‘sum is %d‘%(a+b) @with_arg(‘second‘) def test2(): print ‘i am test2‘ print test1(1,2) test2() 结果: start decorate start decorate i am first i am test1 sum is 3 i am second i am test2
类装饰器
未完待续......
以下几位装饰器讲解的比较透彻,知乎大神很多,还需继续学习,自己的理解中有很多错误,欢迎指正。
https://www.zhihu.com/question/26930016
http://blog.csdn.net/bluehawksky/article/details/50372244
借鉴:
http://python.jobbole.com/82344/
以上是关于python装饰器之自己的理解,欢迎更正的主要内容,如果未能解决你的问题,请参考以下文章
python进阶之装饰器之2.定义一个可接受参数的装饰器如何定义一个属性可由用户修改的装饰器定义一个能接受可选参数的装饰器