1. 程式人生 > >Python裝飾器的理解

Python裝飾器的理解

Python裝飾器是什麼

Python裝飾器就是一個函式,它的產生是為了在不改變目標函式結構的基礎上為其增加功能,返回值是增加功能後的目標函式。

一個簡單的裝飾器 -為程式新增簡單的計時功能

import time

def get_run_time(method):
    def wrapper():
        start = time.time()
        method()
        end = time.time()
        return end - start
    return wrapper

@get_run_time
def helloworld
():
print('helloworld') if __name__ == '__main__': spend = helloworld() print('spend time: {}'.format(spend))

執行結果:

... 
helloworld
spend time: 1.50203704834e-05

目標函式帶引數的情況

當然有時候目標函式(在上面的程式中為helloworld函式)是有引數的,下面做一些微小的改動

import time

def get_run_time(method):
    def wrapper(*args, **kwargs)
:
start = time.time() method(*args, **kwargs) end = time.time() return end - start return wrapper @get_run_time def helloworld(name): print('I\'m {}, helloworld'.format(name)) if __name__ == '__main__': spend = helloworld('wk') print('spend time: {}'
.format(spend))

執行結果:

... 
I'm wk, helloworld
spend time: 2.09808349609e-05

裝飾器函式帶引數的情況

既然裝飾器是個函式,那它也是可以有引數的,此時只要將上述程式碼稍加改動即可

import time

def get_run_time(decimal):
    def wrapper_of_wrapper(method):
        def wrapper(*args, **kwargs):
            start = time.time()
            method(*args, **kwargs)
            end = time.time()
            return round(end - start, decimal)
        return wrapper
    return wrapper_of_wrapper

@get_run_time(decimal=16)
def helloworld(name):
    print('I\'m {}, helloworld'.format(name))

if __name__ == '__main__':
    spend = helloworld('wk')
    print('spend time: {}'.format(spend))
    # 下面這行先不用看,這是下一個標題的內容
    print(helloworld.__name__)

增加了控制返回時間精度的功能,其實就是在原基礎上多封了一層,最外層是新增的一層,目的是增加一個相對全域性變數(能看懂就行了,能力有限,就不扯深的了),在上述程式碼中是decimal

執行結果:

... 
I'm wk, helloworld
spend time: 4.60147857666e-05
wrapper

@functools.wraps

裝飾器返回的函式雖然結構與目標函式相似,但本質已經發生了變話,返回的是另一個函式,看上面程式中print(helloworld.__name__)的輸出為wrapper,再看看functools.wraps的效果

import time
import functools

def get_run_time(decimal):
    def wrapper_of_wrapper(method):
        @functools.wraps(method)
        def wrapper(*args, **kwargs):
            start = time.time()
            method(*args, **kwargs)
            end = time.time()
            return round(end - start, decimal)
        return wrapper
    return wrapper_of_wrapper

@get_run_time(decimal=16)
def helloworld(name):
    print('I\'m {}, helloworld'.format(name))

if __name__ == '__main__':
    spend = helloworld('wk')
    print('spend time: {}'.format(spend))
    # 對比一下,只增加了@functools.wraps
    print(helloworld.__name__)

執行結果:

... 
I'm wk, helloworld
spend time: 2.09808349609e-05
helloworld