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

分享一下我的偶像大神的人工智能教程!http://blog.csdn.net/jiangjunshow

也欢迎转载我的文章,转载请注明出处 https://blog.csdn.net/mm2zzyzzp

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

  继续考察@log 装饰器:

def log(f):
    def fn(x):
        print 'call ' + f.__name__ + '()...'
        return f(x)
    return fn
  
  
  • 1
  • 2
  • 3
  • 4
  • 5

  发现对于被装饰的函数,log打印的语句是不能变的(除了函数名)。
  如果有的函数非常重要,希望打印出’[INFO] call xxx()…’,有的函数不太重要,希望打印出’[DEBUG] call xxx()…’,这时,log函数本身就需要传入’INFO’或’DEBUG’这样的参数,类似这样:

@log('DEBUG')
def my_func():
    pass
  
  
  • 1
  • 2
  • 3

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

my_func = log('DEBUG')(my_func)
  
  
  • 1

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

log_decorator = log('DEBUG')
my_func = log_decorator(my_func)
  
  
  • 1
  • 2

  上面的语句又相当于:

log_decorator = log('DEBUG')
@log_decorator
def my_func():
    pass
  
  
  • 1
  • 2
  • 3
  • 4

  所以,带参数的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()
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

执行结果:
[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)
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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

举例

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

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

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

my_func = performance('ms')(my_func)
  
  
  • 1

需要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)
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17


这里写图片描述

分享一下我的偶像大神的人工智能教程!http://blog.csdn.net/jiangjunshow

也欢迎转载我的文章,转载请注明出处 https://blog.csdn.net/mm2zzyzzp

猜你喜欢

转载自blog.csdn.net/mm2zzyzzp/article/details/83075059