python筆記36-裝飾器之wraps

前言

前面一篇對python裝飾器有了初步的瞭解了,可是還不夠完美,領導看了後又提出了新的需求,但願運行的日誌能顯示出具體運行的哪一個函數。python

__name__和doc

__name__用於獲取函數的名稱,__doc__用於獲取函數的docstring內容(函數的註釋)app

import time

def func_a(a):
    '''func_a --> hello'''
    print("hello"+a)
    time.sleep(0.5)
    return True


def func_b(b, c="xx"):
    '''func_b --> world'''
    print("world"+b+c)
    time.sleep(0.8)
    return True

if __name__ == '__main__':
    print(func_a.__name__)  # 結果 func_a
    print(func_a.__doc__)   # func_a --> hello
    print(func_b.__name__)  # func_b
    print(func_b.__doc__)   # func_b --> world

裝飾器加函數名稱日誌

在裝飾器裏面添加2行代碼,打印正在運行函數的名稱和docstring內容函數

import time


def runtime(func):
    '''runtime decorators'''
    def wrapper(*args, **kwargs):
        '''wrapper inner fuction'''
        print("running function : %s" % func.__name__)   
        print("docstring: %s" % func.__doc__)
        start = time.time()
        f = func(*args, **kwargs)     # 原函數
        end = time.time()
        print("運行時長:%.4f 秒" % (end-start))
        return f
    return wrapper


@runtime
def func_a(a):
    '''func_a --> hello'''
    print("hello"+a)
    time.sleep(0.5)
    return True


@runtime
def func_b(b, c="xx"):
    '''func_b --> world'''
    print("world"+b+c)
    time.sleep(0.8)
    return True

if __name__ == '__main__':
    func_a("a")
    print(func_a.__name__)
    print(func_a.__doc__)

運行結果日誌

running function : func_a
docstring: func_a --> hello
helloa
運行時長:0.5008 秒
wrapper
wrapper inner fuction

從運行的結果能夠看出,func_a.__name__運行的結果是wrapper,func_a.__doc__運行的結果是wrapper inner fuction。
也就是說被裝飾後的函數其實已是另一個函數了(函數名等函數屬性會發生改變),那這個問題如何解決呢?
這就須要用到functools裏面的一個wraps函數了code

functools

當func_a函數被裝飾後,致使了一個反作用:自身的函數屬性和docstring內容變成了wrapper函數的屬性了。
這裏需用到functools裏面的一個wraps的裝飾器來消除這樣的反作用。string

import time
from functools import wraps

def runtime(func):
    '''runtime decorators'''
    @wraps(func)
    def wrapper(*args, **kwargs):
        '''wrapper inner fuction'''
        print("running function : %s" % func.__name__)
        print("docstring: %s" % func.__doc__)
        start = time.time()
        f = func(*args, **kwargs)     # 原函數
        end = time.time()
        print("運行時長:%.4f 秒" % (end-start))
        return f
    return wrapper

只需在wrapper函數上加上@wraps(func)便可解決it

運行結果自動化

running function : func_a
docstring: func_a --> hello
helloa
運行時長:0.5004 秒
func_a
func_a --> hello

類裝飾器

帶參數的裝飾器,能夠寫成類裝飾器io

import time
from functools import wraps

class runtime(object):
    '''runtime class decorators'''
    def __init__(self, slowly=1):
        self.slowly = slowly

    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            '''wrapper inner fuction'''
            print("running function : %s" % func.__name__)
            print("docstring: %s" % func.__doc__)
            start = time.time()
            f = func(*args, **kwargs)     # 原函數
            end = time.time()
            t = end-start
            time.sleep((self.slowly-1)*t)  # 延遲效果
            new_end = time.time()
            print("運行時長:%.4f 秒" % (new_end-start))
            return f
        return wrapper


@runtime(1.5)
def func_a(a):
    '''func_a --> hello'''
    print("hello"+a)
    time.sleep(0.5)
    return True


@runtime()
def func_b(b, c="xx"):
    '''func_b --> world'''
    print("world"+b+c)
    time.sleep(0.8)
    return True

if __name__ == '__main__':
    func_a("a")
    print(func_a.__name__)
    print(func_a.__doc__)

運行結果function

running function : func_a
docstring: func_a --> hello
helloa
運行時長:0.7522 秒
func_a
func_a --> hello

python自動化交流 QQ羣:779429633

相關文章
相關標籤/搜索