Python 进阶 (八) 编写带参数 decorator

继续考察@log 装饰器:

def log(f):    def fn(x):        print 'call ' + f.__name__ + '()...'        return f(x)    return fn

发现对于被装饰的函数,log 打印的语句是不能变的(除了函数名)。

如果有的函数非常重要,希望打印出'[INFO] call xxx()...',有的函数不太重要,希望打印出'[DEBUG] call xxx()...',这时,log 函数本身就需要传入'INFO'或'DEBUG'这样的参数,类似这样:

@log('DEBUG')def my_func():    pass

把上面的定义翻译成高阶函数的调用,就是:

my_func = log('DEBUG')(my_func)

上面的语句看上去还是比较绕,再展开一下:

log_decorator = log('DEBUG')my_func = log_decorator(my_func)

上面的语句又相当于:

log_decorator = log('DEBUG')@log_decoratordef my_func():    pass

所以,带参数的 log 函数首先返回一个 decorator 函数,再让这个 decorator 函数接收 my_func 并返回新函数:

def log(prefix):    def log_decorator(f):        def wrapper(*args, **kw):            print '[%s] %s()...' % (prefix, f.__name__)            return f(*args, **kw)        return wrapper    return log_decorator
@log('DEBUG')def test():    passprint test()

执行结果:

[DEBUG] test()...

对于这种 3 层嵌套的 decorator 定义,你可以先把它拆开:

# 标准decorator:def log_decorator(f):    def wrapper(*args, **kw):        print '[%s] %s()...' % (prefix, f.__name__)        return f(*args, **kw)    return wrapperreturn log_decorator
# 返回decorator:def log(prefix):    return log_decorator(f)

拆开以后会发现,调用会失败,因为在 3 层嵌套的 decorator 定义中,最内层的 wrapper 引用了最外层的参数 prefix,所以,把一个闭包拆成普通的函数调用会比较困难。不支持闭包的编程语言要实现同样的功能就需要更多的代码。

在 @performance 实现打印秒的同时,请给 @performace 增加一个参数,允许传入's'或'ms':

@performance('ms')def factorial(n):    return reduce(lambda x,y: x*y, range(1, n+1))

要实现带参数的 @performance,就需要实现:

my_func = performance('ms')(my_func)

需要 3 层嵌套的 decorator 来实现。参考代码:

import timedef performance(unit):    def perf_decorator(f):        def wrapper(*args, **kw):            t1 = time.time()            r = f(*args, **kw)            t2 = time.time()            t = (t2 - t1) * 1000 if unit=='ms' else (t2 - t1)            print 'call %s() in %f %s' % (f.__name__, t, unit)            return r        return wrapper    return perf_decorator
@performance('ms')def factorial(n):    return reduce(lambda x,y: x*y, range(1, n+1))print factorial(10)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值