pre.cjk { font-family: "Nimbus Mono L", monospace }
h2.western { font-family: "Liberation Sans", sans-serif; font-size: 16pt }
h2.cjk { font-family: "Noto Sans CJK SC Regular"; font-size: 16pt }
h2.ctl { font-family: "FreeSans"; font-size: 16pt }
p { margin-bottom: 0.1in; line-height: 120% }
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)
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
闭包中传递的参数是函数
例子二:
#_*_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()
h2.western { font-family: "Liberation Sans", sans-serif; font-size: 16pt }
h2.cjk { font-family: "Noto Sans CJK SC Regular"; font-size: 16pt }
h2.ctl { font-family: "FreeSans"; font-size: 16pt }
p { margin-bottom: 0.1in; line-height: 120% }
装饰器
例子三:效果与例子二是相同的,只不过此处使用装饰器
#_*_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
h3.western { font-family: "Liberation Sans", sans-serif; font-size: 14pt }
h3.cjk { font-family: "Noto Sans CJK SC Regular"; font-size: 14pt }
h3.ctl { font-family: "FreeSans"; font-size: 14pt }
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
如果被装饰的函数带参数呢
例子四:
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
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
被装饰的函数有返回值?
例子五:
例子五: #_*_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
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
函数被装饰多次时,装饰的顺序是怎样?
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
例子六:
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>
td p { margin-bottom: 0in }
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
详细解释一下:
td p { margin-bottom: 0in }
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
# 1 程序创造一个内存空间, makeBold指向这片地址 # 2 程序创造一个内存空间, makeItalian 指向这片地址
# 3 @makeBold要对下面的函数进行装饰,但发现下面不是函数,而是装饰器,那它就等待下面装饰器装饰完成
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
# 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函数
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
# 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完成)
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
装饰器可以如函数调用一样“堆叠“起来,这里有一个更加普遍的例子,使用了多个装饰器:
@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))相同
pre.cjk { font-family: "Nimbus Mono L", monospace }
p { margin-bottom: 0.1in; line-height: 120% }
带参数的装饰器 例子六:
#接收一个参数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/