python装饰器之自己的理解,欢迎更正

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/

时间: 2024-10-18 06:36:49

python装饰器之自己的理解,欢迎更正的相关文章

对Python装饰器的个人理解方法

0.说明 在自己好好总结并对Python装饰器的执行过程进行分解之前,对于装饰器虽然理解它的基本工作方式,但对于存在复杂参数的装饰器(装饰器和函数本身都有参数),总是会感到很模糊,即使这会弄懂了,下一次也很快忘记,其实本质上还是没有多花时间去搞懂其中的细节问题. 虽然网络上已经有很多这样的文章,但显然都是别人的思想,因此自己总是记不牢,所以花点时间自己好好整理一下. 最近在对<Python核心编程>做总结,收获了不少,下面分享一下我自己对于Python装饰器的理解,后面还提供了一个较为复杂的P

python装饰器的简单理解

如果你接触 Python 有一段时间了的话,想必你对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖. 装饰器的使用方法很固定: 先定义一个装饰函数(帽子)(也可以用类.偏函数实现) 再定义你的业务函数.或者类(人)最后把这顶帽子带在这个人头上 Python装饰器就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能. 这个函数的特殊之处在于它的返回值也是一个函数,这个函数是内嵌“原“”函数的函数. # 有两个已经实现的方法def f1(): p

个人关于python装饰器的白痴理解

无参数装饰器 对于python小白来说,python的装饰器简直让人懵逼,不知如何理解,其实按照装饰器的字面意思, 就是把自己定义的函数装饰一遍,然后返回一个新的函数(注意是新的,已经不是本来定义的函数了) 为什么这么说,我用一个装饰器最原始的例子来说明,看一下代码: 1 #装饰函数 2 def decorator(foo): 3 def wrapper(): 4 print 'wrapper' 5 return foo() 6 return wrapper 7 8 #自定义函数 9 def a

Python装饰器之 property()

1. 何为装饰器? 官方定义:装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用.概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能. Python中总共包括三个内置装饰器: ① staticmethod ② classmethod ③ property 更加详细的解释,请点击(传送门) 2. 属性函数 property() 浅谈

python 装饰器的详细理解【多次实验】

demo: 1 # 装饰器其实就是对闭包的使用 2 print('haha嘻嘻') 3 def hot(): 4 print('知道') 5 def dec(fun): 6 print("call dec") 7 def in_dec(): 8 print("call in_dec") 9 # fun() 10 # 必须加上返回语句,不然的话会默认返回None 11 return in_dec 12 hot() 13 @dec 14 def fun(): 15 pr

python装饰器之函数作用域

1.函数作用域LEGB L:local函数内部作用域 E:enclosing函数内部与内嵌函数之间 G:global全局作用域 B:build-in内置作用域 passline = 60 def func(val): passline = 90 if val >= passline: print('pass') else: print('failed') def in_func() print(val) in_func() def Max(val1,val2): return max(val1,

回顾Python装饰器

函数装饰器(function decorator)可以对函数进行“标注”,给函数提供更多的特性. 在理解装饰器之前需要理解闭包(closure).Python3.0 引入了保留关键字 nonlocal,使用闭包同样也离不开 nonlocal.顺便说一句,闭包除了用在装饰器上,对于异步编程也是很重要的概念. 装饰器(decorator)是一个可调用的装饰函数,它接收另一个函数作为参数. 假设已经定义好了一个装饰器 decorate(decorate 实际上是一个接收函数并且返回函数的函数),那么以

关于python装饰器(Decorators)最底层理解的一句话

一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.html 一步步教你理解Python装饰器 我作完了全部的测试.

理解Python装饰器(一)

python装饰器 装饰器是什么?我也不知道该如何给装饰器下定义. 1. 装饰器是函数,因为从代码的层面上来说,它就是开发人员定义的一个函数而已: 2. 装饰器就像是类的继承一样,通过装饰符,来实现函数与函数.函数与类之间的"继承" 3. 装饰器是种特殊的语法,通过 `@函数名` 或者 `@类名` 来实现函数或类的继承,但是 装饰器不是继承,装饰器装饰的函数会被当做参数传递给装饰器,这个功能又好像 C++中的虚函数,装饰器装饰的函数用来修改装饰器本身的功能来实现额外功能的添加. 示例: