python装饰器由浅入深

来源:互联网 发布:mysql gtid主从 编辑:程序博客网 时间:2024/05/22 08:04

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

学习装饰器必需要理解装饰器的执行行为,装饰器主要分为无参数的函数、被装饰的函数有参数、装饰器带参数,在原有装饰器的基础上,设置外部变量、装饰器和闭包混用、类装饰器,能正确理解其执行过程即可。下面每种类型给出一个例子,帮助理解:

1:无参数的函数

from time import ctime, sleepdef timefun(func):    def wrappedfunc():        print("%s called at %s"%(func.__name__, ctime()))        return func()    return wrappedfunc@timefundef foo():    print("I am foo")foo()sleep(2)foo()

运行结果:

foo called at Thu Oct 27 14:53:10 2016I am foo#休眠两秒foo called at Thu Oct 27 14:53:12 2016I am foo

这段代码可以理解为:

foo = timefun(foo)#foo先作为参数赋值给func后,foo接收指向timefun返回的wrappedfuncfoo()#调用foo(),即等价调用wrappedfunc()#内部函数wrappedfunc被引用,所以外部函数的func变量(自由变量)并没有释放#func里保存的是原foo函数对象

2:被装饰的函数有参数

from time import ctime, sleepdef timefun(func):    def wrappedfunc(a, b):        print("%s called at %s"%(func.__name__, ctime()))        print(a, b)        return func(a, b)    return wrappedfunc@timefundef foo(a, b):    print(a+b)foo(3,5)sleep(2)foo(2,4)

运行结果:

foo called at Thu Oct 27 15:03:00 2016(3, 5)8foo called at Thu Oct 27 15:03:02 2016(2, 4)6

这段代码可以理解为:

foo = timefun(foo(a,b))#foo先作为参数赋值给func后,foo接收指向timefun返回的wrappedfuncfoo(a,b)#调用foo(),即等价调用wrappedfunc()#内部函数wrappedfunc被引用,所以外部函数的func变量(自由变量)并没有释放#func里保存的是原foo函数对象

3:装饰器带参数,在原有装饰器的基础上,设置外部变量

from time import ctime, sleepdef timefun_arg(pre="hello"):    def timefun(func):        def wrappedfunc():            print("%s called at %s %s"%(func.__name__, ctime(), pre))            return func()        return wrappedfunc    return timefun@timefun_arg("world")def foo():    print("I am foo")@timefun_arg("xwp")def too():    print("I am too")foo()sleep(2)foo()too()sleep(2)too()

运行结果:

foo called at Thu Oct 27 15:11:09 2016 worldI am foofoo called at Thu Oct 27 15:11:11 2016 worldI am footoo called at Thu Oct 27 15:11:11 2016 xwpI am tootoo called at Thu Oct 27 15:11:13 2016 xwpI am too

可以理解为:

foo()==timefun_arg("world")(foo)()

4:装饰器和闭包混用

#coding=utf-8from time import timedef logged(when):    def log(f, *args, **kargs):        print("fun:%s  args:%r  kargs:%r" %(f, args, kargs))        #%r字符串的同时,显示原有对象类型    def pre_logged(f):        def wrapper(*args, **kargs):            log(f, *args, **kargs)            return f(*args, **kargs)        return wrapper    def post_logged(f):        def wrapper(*args, **kargs):            now=time()            try:                return f(*args, **kargs)            finally:                log(f, *args, **kargs)                print("time delta: %s"%(time()-now))        return wrapper    try:        return {"pre":pre_logged, "post":post_logged}[when]    except KeyError, e:        raise ValueError(e), 'must be "pre" or "post"'@logged("post")def fun(name):    print("Hello, %s"%(name))fun("hellopython!")

运行结果:

Hello, hellopython!fun:<function fun at 0x10f6078c0>  args:('hellopython!',)  kargs:{}time delta: 9.98973846436e-05

执行过程:

return {"pre":pre_logged, "post":post_logged}[post]=post_logged,返回post_logged函数,其余与前面类似,自己琢磨一下就理解了。。。

5:类装饰器

class Itcast(object):     def __init__(self, func):         super(Itcast, self).__init__()         self._func = func     def __call__(self):          print 'class Itcast'          self._func()  @Itcastdef showpy():    print 'showpy'showpy()

要定义类型的时候,实现call函数,这个类型就成为可调用的。 可以把这个类的对象当作函数来使用。

1 0
原创粉丝点击