Python 装饰器归纳总结

来源:互联网 发布:淘宝店铺换ip有影响吗 编辑:程序博客网 时间:2024/06/05 17:00

实际应用中装饰器没少用,像flask的路由功能,都是用装饰器来挂上去的,不过平时装饰器都是看的网上的文章然后在用,自己没总结过

这次单独写一篇笔记,加深印象


先简单讲一下我理解的装饰器的两大特点

1:在不用修改原本函数的情况下,对原来函数的输出结果进行添加功能

2:装饰器是一个高阶函数,他的返回值,是一个函数


普通函数

首先来看个普通函数

def current_time():print ('2016.12.25')f=current_timef()print (current_time.__name__)

这是一个打印当前日期的函数,最后还会打印出函数名字

2016.12.25current_time

可以看到,能打印出函数名字,是因为我们在调用的时候,手工打印了出来,如果你要自动地打印,那你就要修改原本的函数了

这样简单的函数改改还不是问题,如果你在一个大项目里面涉及到很多要改的地方,估计就要吐了。


所以,装饰器就可以提现他的作用了


最简单的装饰器

def simple(f):def inside():print ('here in decorator for function %s'% f.__name__)return freturn inside#调用方法1: 这个是最直接的方法,用@语法糖,这个的作用,和调用方法3的原理是一模一样的,将本体函数current_time传给simple@simpledef current_time(): print ('now')current_time()#调用方法2: 这个需要理解下simple(current_time)了以后,就相当于已经取到返回的inside了,如果你需要执行的话,就在后面再加一对()def current_time(): print ('now')simple(current_time)()#调用方法3 : 装饰器的基本原理,将本体函数以参数的方式传递给装饰器def current_time(): print ('now')current_time=simple(current_time)current_time()


这样一个最简单的装饰器就完成了,当你调用current他的输出结果是



本体函数带参数的装饰器

def current_time(x,y):return x+ydef decorator(f):def wrapper(*args,**kw):return f(*args,**kw)*3return wrapper@decoratordef current_time(x,y):return (x+y)print (current_time(1,2))


可以看到,decorator就是我们装饰器的名字了,他的参数是你需要加强的函数(以下称为本体函数

你还可以看到,wrapper是装饰器内部的函数,他用于加强功能

他的作用是:将本体函数的结果,乘以3

我们来看一下效果


这样,你原来输入的参数1和2,相加结果是3,但是经过装饰器以后,结果就是3倍了。



装饰器本身附带参数

用@来做装饰器,和语句current_time=wrapper(current_time)的作用是一毛一样的。
这里需要特别记住:@这个语法,在这种情况下,只能相当于,将本体函数(这一个参数)传入装饰器函数,没法附带其他的内容

比如,你没法使用  @decorator( 'test_text' ) 这样的语法,他会提示参数错误的。

当然,你如果强行用current_time = decorator(current_time , 'test_text' )这样的写法,也是可以达到同时传入其他参数的目的

但是,这写法的繁琐程度和不用装饰器,没啥区别。



所以,我们引入了带参数的装饰器

平时用的最多的就是flask的路由装饰器了

比如最简单的flask路由

@app.route('/')def index():        return 'hello world'

那要实现这样的功能,如何修改装饰器呢?

这就需要再包括一层装饰器了


def top(text):def decorator(f):def wrapper(*args,**kw):print (text+' of top')return f(*args,**kw)*3return wrapperreturn decorator@top('text for test')def current_time(x,y):return (x+y)print (current_time(1,2))


这样,你的装饰器就可以随意添加你想要加的内容了

效果看下

e:\atry>python de.pytext for test of top9

这样的语句的简单理解写法是 current_time = top('text for test')(current_time)

也就是,先执行 top('text for test'),他返回decorator函数,然后,decorator函数再加上后面的(current_time)作为参数传入


需要注意的地方, name属性已改变

这里要额外提一下,这样装饰器,他的本体参数的__name__属性已改变,如果碰到一些和函数名字撤上关系的功能时,会引发错误

先看名字被改变的测试

print (current_time.__name__)
他打印出的结果是 wrapper,也就是,原来的函数名字已经变成了wrapper


那如何规避这个问题呢?可以用functools里面的wrapper功能,如下

import functoolsdef current_time(x,y):return x+ydef top(text):def decorator(f):@functools.wraps(f)def wrapper(*args,**kw):print (text+' of top')return f(*args,**kw)*3return wrapperreturn decorator@top('text for test')def current_time(x,y):return (x+y)print (current_time(1,2))print (current_time.__name__)


这样,做出来的程序,他的名字就不会被修改了



多重装饰器的先后顺序

有时候你会看到,一个函数上面挂了好几个装饰器,那他们是否有先后顺序呢?

肯定有的,我们来看看多重装饰器是从上往下还是从下往上开始执行

def add_before(f):def wrapper():print (f()+' add_before decorator')return f()+' add_before decorator'return wrapperdef add_later(f):def wrapper():# print (f()+' add_later decorator')return f()+' add_later decorator'return wrapper@add_before@add_laterdef test():return 'here in test'test()

通过下面的效果图,你可以看到,他是先被add_later 装饰器进行了作用,再进行add_before装饰器作用

也就是从最靠近本体函数的地方开始起装饰器作用




这样,装饰器基本的概念就完全了,其他的具体应用,也是基于这些原理之上的。






0 0
原创粉丝点击