章节
问答
笔记
评论
占位
占位

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_decorator
def 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():
    pass
print test()

执行结果:

[DEBUG] test()...
None

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

# 标准decorator:
def log_decorator(f):
    def wrapper(*args, **kw):
        print '[%s] %s()...' % (prefix, f.__name__)
        return f(*args, **kw)
    return wrapper
return 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 time
def 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/150
提交
取消
全部 精华 我要发布
全部 我要发布
最新 点赞
只看我的

手记推荐

更多

本次提问将花费2个积分

你的积分不足,无法发表

为什么扣积分?

本次提问将花费2个积分

继续发表请点击 "确定"

为什么扣积分?