1. 程式人生 > >Python進階(八)-編寫帶引數decorator

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