1.认识装饰器
如果你经常看我的博客,你已经学会了python的前两大‘神器’(迭代器,生成器),那么什么是装饰器呢?就如字面意义装饰器是对某个事物(通常指函数)进行装饰,让其在不修改任何内部代码的情况下增添新的功能,接下来我将一步步的解析python的装饰器。
2.闭包
在解析装饰器之前我们需要先了解下闭包的概念,我们先通过一段代码了解闭包
# 定义一个函数 def test(number): # 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包 def test_in(number_in): print("in test_in 函数, number_in is %d" % number_in) return number+number_in # 其实这里返回的就是闭包的结果 return test_in # 给test函数赋值,这个20就是给参数number ret = test(20) # 注意这里的100其实给参数number_in print(ret(100)) #注 意这里的200其实给参数number_in print(ret(200))
运行结果
in test_in 函数, number_in is 100 120 in test_in 函数, number_in is 200 220
看完这段代码我们不妨总结下闭包的作用:
1.函数名只是函数代码空间的引用,当函数名赋值给一个对象的时候 就是引用传递
2.闭包就是一个嵌套定义的函数,在外层运行时才开始内层函数的定义,然后将内部函数的引用传递函数外的对象
3.内部函数和使用的外部函数提供的变量构成的整体称为闭包
3.初识装饰器
为什么在解释装饰器时要先了解闭包的概念呢?看完下面的代码你也会就会明白
def decorate(func): def inner(): return "<i>"+func()+"</i>" return inner @decorate def func(): return "你好" print(func())
运行结果
<i>你好</i>
我们可以看出装饰器就是在闭包的基础上做了一些修改。
4.装饰器普通传参
from time import ctime, sleep
def timefun(func):
def wrapped_func(a, b):
print("%s called at %s" % (func.__name__, ctime()))
print(a, b)
func(a, b)
return wrapped_func
@timefun
def foo(a, b):
print(a+b)
foo(3,5)
sleep(2)
foo(2,4)
运行结果
foo called at Thu Aug 23 21:30:21 2018 3 5 8 foo called at Thu Aug 23 21:30:23 2018 2 4 6
5.装饰器不定长传参
from time import ctime, sleep def timefun(func): def wrapped_func(*args, **kwargs): print("%s called at %s"%(func.__name__, ctime())) func(*args, **kwargs) return wrapped_func @timefun def foo(a, b, c): print(a+b+c) foo(1,2,3) sleep(1) foo(4,5,6)
运行结果
foo called at Thu Aug 23 21:32:50 2018 6 foo called at Thu Aug 23 21:32:51 2018 15
其实这里只是运用了python函数传参时的不定长传参的概念
6.装饰器中的return
from time import ctime, sleep def timefun(func): def wrapped_func(): print("%s called at %s" % (func.__name__, ctime())) func() return wrapped_func @timefun def foo(): print("I am foo") @timefun def getInfo(): return '----hahah---' foo() sleep(2) foo() print(getInfo())
运行结果
foo called at Thu Aug 23 21:36:22 2018 I am foo foo called at Thu Aug 23 21:36:24 2018 I am foo getInfo called at Thu Aug 23 21:36:24 2018 None
7.装饰器工厂(flask定义一个路由的方式)
from time import ctime, sleep def timefun_arg(pre="hello"): def timefun(func): def wrapped_func(): print("%s called at %s %s" % (func.__name__, ctime(), pre)) return func() return wrapped_func return timefun @timefun_arg("php") def foo(): print("I am foo") @timefun_arg("python") def too(): print("I am too") foo() sleep(2) foo() too() sleep(2) too()
运行结果
foo called at Thu Aug 23 21:40:34 2018 php I am foo foo called at Thu Aug 23 21:40:36 2018 php I am foo too called at Thu Aug 23 21:40:36 2018 python I am too too called at Thu Aug 23 21:40:38 2018 python I am too
我们分析下装饰器工厂装饰过程
1. 调用timefun_arg("itcast")
2. 将步骤1得到的返回值,即time_fun返回, 然后time_fun(foo)
3. 将time_fun(foo)的结果返回,即wrapped_func
4. 让foo = wrapped_fun,即foo现在指向wrapped_func
8.类装饰器
class Test(object): def __init__(self, func): print("初始化中....") print("func name is %s"%func.__name__) self.__func = func def __call__(self): print("装饰中......") self.__func() @Test def test(): print("----test---") test()
运行结果
初始化中.... func name is test 装饰中...... ----test---
我们也许会发现装饰器中有个很特别的方法__call__(),这个方法时python内置的魔法方法,它作用就是让类能够向函数一样直接被调用,接下来我会专门更新一篇python中的魔法方法,如果想要了解的朋友可以关注我
总结
1.装饰器函数只有一个参数就是被装饰的函数的应用
2.装饰器能够将一个函数的功能在不修改代码的情况下进行扩展
3.在函数定义的上方@装饰器函数名 即可直接使用装饰器对下面的函数进行装饰。