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指向的函数体,这可以帮助我们在不改变函数内部结构的情况下,增加它的功能(也就是对其装饰,比如对其增加一个验证功能,增加收集日志的功能)。@testtest3 = 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就指向了Italianwords就指向makeBold返回值,也就是Bold函数
# 6 调用words()后,执行Bold(),打印‘make words Bold‘
执行到fn()时进入Italian(),打印‘make words italian‘
执行到fn()时进入FFFF(),返回hello ParisFFFF完成);
返回<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中的装饰器之写一个装饰器

Python装饰器之 property()

Python装饰器之 property()

python进阶之装饰器之2.定义一个可接受参数的装饰器如何定义一个属性可由用户修改的装饰器定义一个能接受可选参数的装饰器

python装饰器之property

Python:装饰器之有参装饰器