初窺Python(五)——python中的decorator

來源:互聯網
上載者:User

標籤:python   decorator   


1. 介紹

decorator是用來在代碼運行期間動態增加功能的,本質上是一個返回函數的高階函數。假設現在有這樣一種需求,即在每個函數調用前記錄日誌,記錄被調用的函數名稱,可以這樣實現:

def log(func):    def wrapper(*args, **kwargs):        print "CALL %s()" % func.__name__        return func(*args, **kwargs)    return wrapperdef sayHi():    print "Hi, Buddy."def sayHello():    print "Hello, Buddy."# 調用函數,記錄日誌log(sayHi)()# 輸出為# CALL sayHi()# Hi, Buddy.log(sayHello)()# 輸出為# CALL sayHello()# Hello, Buddy.

這種方法確實實現了記錄日誌的功能,但每次這麼調用未免太過繁瑣,decorator因此出現。

2. 使用

其實,之前定義的log函數即為一個decorator,只是使用方式不正確:

@logdef sayHi():    print "Hi, Buddy."sayHi()# 輸出為# CALL sayHi()# Hi, Buddy.@logdef sayHello():    print "Hello, Buddy."sayHello()# 輸出為# CALL sayHello()# Hello, Buddy.

可以看到,使用decorator非常簡單方便,def sayHi():前的@log相當於將sayHi作為參數傳入log函數中,並將傳回值賦給sayHi,即:

sayHi = log(sayHi)

但是細心的讀者不難發現,這樣一來函數sayHi__name__屬性發生變化,由之前的sayHi變為wrapper,使用python內建的functools.wraps方法可以解決這一問題,改造後的decorator如下:

import functools def log(func):    @functools.wraps(func)    def wrapper(*args, **kwargs):        print "CALL %s()" % func.__name__        return func(*args, **kwargs)    return wrapper

讓我們更進一步,使用三層嵌套的decorator,允許再多傳入一次參數:

import functoolsdef log(text="CALL")    def decorator(func):        @functools.wraps(func)        def wrapper(*args, **kwargs):            print "%s %s()" % (text, func.__name__)            return func(*args, **kwargs)        return wrapper    return decorator

這次我們可以選擇傳入一個表示函數運行狀態的字串,由於多了一層嵌套,使用時也會有些變化:

@log("EXECUTE")def sayHi():    print "Hi, Buddy."sayHi()# 輸出為# EXECUTE sayHi()# Hi, Buddy.

修改過後嵌套使用為:

sayHi = log("EXECUTE")(sayHi)
3. 拓展3.1

修改log函數,使該decorator既可以通過

@log

使用,又可以通過

@log("EXECUTE")

使用:

import functoolsdef log(text="CALL"):    if callable(text):        func = text        @functools.wraps(func)        def wrapper(*args, **kwargs):            print "CALL %s()" % func.__name__            return func(*args, **kwargs)    else:        def decorator(func):            @functools.wraps(func)            def wrapper(*args, **kwargs):                print "%s %s()" % (text, func.__name__)                return func(*args, **kwargs)            return wrapper        return decorator

兩種使用方式:

@logdef sayHi():    print "Hi, Buddy."sayHi()# 輸出為# CALL sayHi()# Hi, Buddy.@log("EXECUTE")def sayHello():    print "Hello, Buddy."sayHello()# 輸出為# EXECUTE sayHello()# Hello, Buddy.
3.2

修改log函數,使該decorator在函數調用前及函數調用後分別輸出一條日誌:

import functoolsdef log(func):    def wrapper(*args, **kwargs):        print "CALL BEGINNING"        call = func(*args, **kwargs)        print "CALL ENDING"        return call    return wrapper

使用該decorator

@logdef sayHi():    print "Hi, Buddy."sayHi()# 輸出為# CALL BEGINING# Hi, Buddy.# CALL ENDING
參考資料:

廖雪峰的官方網站

本文出自 “細桶假狗屎” 部落格,請務必保留此出處http://xitongjiagoushi.blog.51cto.com/9975742/1683554

初窺Python(五)——python中的decorator

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.