Python装饰器

在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。

本质上,decorator就是一个返回函数的高阶函数。

装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。

1.不带参数的装饰器调用 

@是装饰器的语法糖,在定义的时候使用,防止再一次的赋值

通过装饰器log在调用函数前输出调用函数的名称

def log(func):
    def wrapper(*args, **kw):
        print "call %s !" % func.__name__
        return func(*args, **kw)
    return wrapper


@log
def print1():
    print 1
print1()

结果为

call print1 !
1

由于log()是一个decorator,返回一个函数,所以,原来的print1()函数仍然存在,只是现在同名的print1变量指向了新的函数,于是调用print1()将执行新函数,即在log()函数中返回的wrapper()函数。

2.需要传入参数的装饰器

当装饰器需要传入参数时,需要三层返回函数的调用

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print "%s %s !" % (text, func.__name__)
            return func(*args, **kw)
        return wrapper
    return decorator


@log("excute")
def print1():
    print 1


print1()
excute print1 !
1

等同于:

print1 = log("excute")(print1)

首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是print1函数,返回值最终是wrapper函数

3.解决装饰器调用函数改变 函数属性 -- __name__ 的问题

print print1.__name__

输出

wrapper

因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

在这我们使用functools 提供的 wrap方法

import functools


def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print "%s %s !" % (text, func.__name__)
            return func(*args, **kw)
        return wrapper
    return decorator


@log("excute")
def print1():
    print 1


print1()
print print1.__name__

在wrapper函数前加上装饰器 @functools.wraps(func)即可

输出结果:

excute print1 !
1
print1

4.做一个廖大大课后小练习

请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:

#import time,functools

def printcalltime(fun):
   @functools.wrap(fun)
def wrapper(*args, **kw): start = time.time() res = fun(*args, **kw) end = time.time() print "%s excute time = %d ms !" %(fun.__name__, (end - start) * 1000)
     return res
return wrapper @printcalltime def print1(): time.sleep(2) print 1 print1()
print print1.__name__

结果为

1
print1 excute time = 1000 ms !
print1

5.多个装饰器的执行顺序

@a
@b
@c
def func():
    print "aaa"

等同于

a(b(c(fun)))

6.Python内置装饰器

@property  --  类似C++中private修饰 将类方法中的变量变为 静态 只读状态

@staticmethod -- 类似C++中静态函数 可以不用通过类实例调用被其装饰过的函数 即将函数自带的self参数去掉

@classmethod -- 类方法 将方法中的参数由self类实例 变为 cls即类名 

posted @ 2017-12-21 21:12  BeBestJackie  阅读(2463)  评论(0编辑  收藏  举报