Python 裝飾器

按照python官方文檔,函數(shù)定義可以被一個(gè)或者多個(gè)decorator包起來(lái),解釋如下:

@f1(arg)
@f2
def func(): pass

等同于

def func(): pass
func = f1(arg)(f2(func))

而且:Decorator expressions are evaluated when the function is defined, in the scope that contains the function definition


Example 1. 無(wú)參數(shù)裝飾器

def hello(fn):
    def wrapper():
        print "hello, %s" % fn.__name__
        fn()
        print "goodby, %s" % fn.__name__
    return wrapper
 
@hello
def foo():
    print "i am foo"

解釋

  • 編譯器做如下轉(zhuǎn)換:
@hello
def foo     # ===> hello(foo)
  • foo = hello(foo) = wrapper
  • foo此時(shí)僅僅是一個(gè)函數(shù),沒(méi)有被調(diào)用,foo()才會(huì)調(diào)用

這種裝飾器,僅僅將在已有函數(shù)的基礎(chǔ)之上,附加額外的裝飾功能。
到底什么時(shí)候調(diào)用,由使用者決定


Example 2. 帶參數(shù)裝飾器

def hello(dummy=""):
    def wrapper(fn):
        print "hello, %s" % fn.__name__
        fn()
        print "goodby, %s" % fn.__name__
    return wrapper
 
@hello("")
def foo():
    print "i am foo"

解釋

  • 編譯器做如下轉(zhuǎn)換:
@hello("")
def foo     # ===> hello("")(foo)
  • foo = hello("")(foo)
  • hello("") = wrapper
  • foo = wrapper(foo)
  • 此時(shí)編譯器已經(jīng)執(zhí)行wrapper函數(shù)
  • 由于wrapper沒(méi)有返回值,foo=None

這種裝飾器就不一樣了,函數(shù)定義期間就被賦予執(zhí)行的行為
設(shè)想:這可以被用來(lái)做某些初始化動(dòng)作

從上面的例子分析可以看到,被decorator的函數(shù)其實(shí)已經(jīng)是另外一個(gè)函數(shù)了,對(duì)于最前面那個(gè)hello.py的例子來(lái)說(shuō),如果你查詢(xún)一下foo.__name__的話,你會(huì)發(fā)現(xiàn)其輸出的是“wrapper”,而不是我們期望的“foo”,這會(huì)給我們的程序埋一些坑。所以,Python的functool包中提供了一個(gè)叫wrap的decorator來(lái)消除這樣的副作用

from functools import wraps
def hello(fn):
    @wraps(fn)
    def wrapper():
        print "hello, %s" % fn.__name__
        fn()
        print "goodby, %s" % fn.__name__
    return wrapper
 
@hello
def foo():
    '''foo help doc'''
    print "i am foo"
    pass
 
foo()
print foo.__name__ #輸出 foo
print foo.__doc__  #輸出 foo help doc

應(yīng)用1. 給函數(shù)調(diào)用做緩存

from functools import wraps
def memo(fn):
    cache = {}
    miss = object()
 
    @wraps(fn)
    def wrapper(*args):
        result = cache.get(args, miss)
        if result is miss:
            result = fn(*args)
            cache[args] = result
        return result
 
    return wrapper
 
@memo
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

應(yīng)用2. 注冊(cè)回調(diào)函數(shù)

class MyApp():
    def __init__(self):
        self.func_map = {}
 
    def register(self, name):
        def func_wrapper(func):
            self.func_map[name] = func
            return func
        return func_wrapper
 
    def call_method(self, name=None):
        func = self.func_map.get(name, None)
        if func is None:
            raise Exception("No function registered against - " + str(name))
        return func()
 
app = MyApp()
 
@app.register('/')
def main_page_func():
    return "This is the main page."
 
@app.register('/next_page')
def next_page_func():
    return "This is the next page."
 
print app.call_method('/')
print app.call_method('/next_page')

參考自:coolshell

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 每個(gè)人都有的內(nèi)褲主要功能是用來(lái)遮羞,但是到了冬天它沒(méi)法為我們防風(fēng)御寒,咋辦?我們想到的一個(gè)辦法就是把內(nèi)褲改造一下,...
    chen_000閱讀 1,373評(píng)論 0 3
  • Python裝飾器的高級(jí)用法(翻譯) 原文地址https://www.codementor.io/python/t...
    城南道閱讀 4,827評(píng)論 1 22
  • 一. 有時(shí)候我們會(huì)有這樣需求: 在原有的邏輯前后添加一段邏輯 如: 在增/刪/改操作之前檢查用戶是否登錄、某個(gè)操...
    元亨利貞o閱讀 698評(píng)論 1 4
  • 裝飾器簡(jiǎn)述 要理解裝飾器需要知道Python高階函數(shù)和python閉包,Python高階函數(shù)可以接受函數(shù)作為參數(shù),...
    XYZeroing閱讀 280評(píng)論 0 1
  • 1、寫(xiě)在前面 在學(xué)習(xí)數(shù)據(jù)庫(kù)的時(shí)候有很多疑問(wèn),期間整理了一下內(nèi)容,在此記錄以供后期學(xué)習(xí) 2、博客列表 001--Or...
    糖紙瘋了閱讀 446評(píng)論 0 0