Python裝飾器函數(shù)怎么使用

這篇文章主要介紹了Python裝飾器函數(shù)怎么使用的相關(guān)知識,內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Python裝飾器函數(shù)怎么使用文章都會有所收獲,下面我們一起來看看吧。

成都創(chuàng)新互聯(lián)公司于2013年創(chuàng)立,先為連山等服務(wù)建站,連山等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為連山企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

Python裝飾器函數(shù)怎么使用

假如我寫了一個函數(shù) f

def f():
    print('hello')

之后我想知道這段函數(shù)執(zhí)行所要的時間,這好辦,我只要將代碼改為如下就行

import time
def f():
    start = time.time()   #獲取程序執(zhí)行開始的時間
    print('hello')
    end = time.time()     #獲取程序執(zhí)行結(jié)束的時間
    print(end - start)    #得出函數(shù)f執(zhí)行所要時間

f()

但之后我有寫了無數(shù)個函數(shù)f2,f3……fn,我想知道每個函數(shù)執(zhí)行所需要的時間,那么如果都像上面一樣改,豈不是很鬧心?還是不行,因?yàn)檫@樣實(shí)在是太麻煩了。那怎么辦呢?于是靈機(jī)一動,寫了一個timer函數(shù)。。。

import time
def timer(func):
    start = time.time()
    func()
    print(time.time() - start)

def f():
    print('hello')


def f2():
    print('xorld')

timer(f)
timer(f2)

這樣看起來是不是簡單多啦?不管我們寫了多少個函數(shù)都可以調(diào)用這個計(jì)時函數(shù)來計(jì)算函數(shù)的執(zhí)行時間

但是如果我只想用原來的方式f1(),f2(),fn()調(diào)用了這個函數(shù),函數(shù)在原本執(zhí)行輸出的結(jié)果不變的前提下還可以增加計(jì)算時間的功能,而不是調(diào)用timer(f),timer(f2)才能計(jì)算時間,這該怎么辦呢?

看了下面的裝飾器函數(shù)你就會知道如何解決這個問題



一、裝飾器 —— 形成過程

以下就是解決上面問題的代碼的簡單版:

import time

def f():
    print('hello')

def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

f = timer(f)
f()

還是這句話我只想用原來的方式f1(),f2(),fn()調(diào)用了這個函數(shù),函數(shù)在原本執(zhí)行輸出的結(jié)果不變的前提下還可以增加計(jì)算時間的功能,但我還是要在函數(shù) f 執(zhí)行前寫 f = timer(f)在這一串代碼,是不是覺得礙眼?python的開發(fā)者也覺得礙眼,所以python的開發(fā)者就為我們提供了一句語法糖來解決這個問題!



二、裝飾器 —— 初識語法糖

用@timmer代替f = timer(f),這就是一句語法糖。

import time
def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner

@timer   #==> 寫著這句話就相當(dāng)于執(zhí)行了f = timer(f)
def f():
    print('hello')


f()


三、裝飾器 ——本質(zhì)與功能

1、本質(zhì)

  裝飾器的本質(zhì)就是一個閉包函數(shù)

2、功能

在不修改原函數(shù)及其調(diào)用方式的情況下對原函數(shù)功能進(jìn)行擴(kuò)展

四、裝飾器 —— 裝飾帶參數(shù),返回值的裝飾器

  • 1、裝飾帶一個參數(shù)的函數(shù)

剛才我們寫的裝飾器都是裝飾不帶參數(shù)的函數(shù),現(xiàn)在要裝飾一個帶參數(shù)的函數(shù)怎么辦呢?

import time
def timer(func):
    def inner(a):
        start = time.time()
        func(a)
        print(time.time() - start)
    return inner

@timer
def f(a):
    print(a)

f('hello')
  • 2、裝飾多個帶有不同參數(shù)但無返回值的函數(shù)

其實(shí)裝飾帶參的函數(shù)并不是什么難事,但假如你有兩個函數(shù),需要傳遞的參數(shù)不一樣呢,比如  函數(shù)func1有兩個參數(shù)func1(a ,b),函數(shù)func 2只有一個參數(shù)func2(a), 且它們都想用這個裝飾器裝飾,做到計(jì)算函數(shù)執(zhí)行時間?這怎么辦呢?那就用下面代碼。

import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func1 = timer(func1)
def func1(a,b):
    print('in func1')

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))

輸出結(jié)果:
in func1
0.0
in func2 and get a:aaaaaa
0.0
fun2 over
  • 3、裝飾多個帶有不同參數(shù)且有返回值的函數(shù)

現(xiàn)在參數(shù)的問題已經(jīng)完美的解決了,可是如果你的函數(shù)是有返回值的呢?用上面的代碼你就拿不到返回值了那究竟要如何解決這個問題呢?那就看下面的代碼吧!

import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func2('aaaaaa')
print(func2('aaaaaa'))

輸出結(jié)果:
in func2 and get a:aaaaaa
0.0
in func2 and get a:aaaaaa
0.0
fun2 over
  • 4、多個裝飾器裝飾同一個函數(shù)

有些時候,我們也會用到多個裝飾器裝飾同一個函數(shù)的情況。

ef wrapper1(func):   #func ----- f
    def inner1():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner2

@wrapper2       #f = wrapper2(f) ----->> wrapper2(inner1)  == inner2
@wrapper1       #f = wrapper1(f) = inner
def f():
    print('in f')
f()    #===>>inner2
#多個裝飾器裝飾同一個函數(shù)

輸出結(jié)果:
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func


五、裝飾器 ——  裝飾器進(jìn)階與優(yōu)化

  • 1、帶參數(shù)的裝飾器

上面那個裝飾器已經(jīng)非常beautiful了,但是還有一個問題,如果我給代碼中無數(shù)個函數(shù)都加了@timer這個語法糖,如果之后我又不想用它了那豈不是又要每個去將它注釋,沒日沒夜忙活3天?豈不是特別麻煩,為了使裝飾器不用時能夠更好的回收而不是一個一個去注釋或者刪除 我們引入帶參數(shù)的裝飾器概念

'''
為了使裝飾器不用時能夠更好的回收而不是一個一個去注釋或者刪除
我們引入帶參數(shù)的裝飾器概念
'''

import time
'''FLAGE的目的是用它控制裝飾器的開關(guān),
那么當(dāng)我們不用的時候就不要一個一個去注釋只需將True改為False就行'''

FLAGE = True
def timmer_out(flag):
    def timmer(func):
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                ret = func(*args,**kwargs)
                end = time.time()
                print(end - start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return timmer
@timmer_out(FLAGE)

#timmer_out(FLAGE)
# 也相當(dāng)于執(zhí)行  timmer_out(FLAGE)--->>返回timmer———————>>@timmer(wahaha = timmer(wahaha))
def wahaha():
    time.sleep(0.1)         #不休息的話函數(shù)執(zhí)行的太快難以計(jì)算時間
    print('wahahahahahaha')

wahaha()

@timmer_out(FLAGE)
def erguotou():
    time.sleep(0.1)         #不休息的話函數(shù)執(zhí)行的太快難以計(jì)算時間
    print('erguotoutoutou')

erguotou()

輸出結(jié)果:
wahahahahahaha
0.10152268409729004
erguotoutoutou
0.10795140266418457
  • 2、防止函數(shù)必要信息失效

'''
print(wahaha.__name__)      #查看字符串格式的函數(shù)名
print(wahaha.__doc__)       #查看一個函數(shù)的注釋
'''
#下面用__name__查看holiday的函數(shù)名

from functools import wraps
def wrapper(func):
    @wraps(func)            #加在最內(nèi)層函數(shù)正上方
    def inner(*args,**kwargs):
        print('在被裝飾的函數(shù)執(zhí)行之前做的事')
        ret = func(*args,**kwargs)
        print('在被裝飾的函數(shù)執(zhí)行之后做的事')
        return ret
    return inner

@wrapper        #holiday = wrapper(holiday)
def holiday(day):
    '''
    這是一個放假通知
    :param day:
    :return:
    '''
    print('全體放假%s天'%day)
    return '好開心'

print(holiday.__name__)
print(holiday.__doc__)
'''
結(jié)果是inner和None 但我們想要的是打印holiday的字符串格式的函數(shù)名和函數(shù)的注釋這時該怎么辦?
解決方法就是  from functools import wraps
使用語法是@wraps(被裝飾的函數(shù)名)
'''

輸出結(jié)果:
holiday

    這是一個放假通知
    :param day:
    :return:


六、裝飾器 —— 裝飾原則

  • 1、開放封閉原則

1.對原函數(shù)的功能擴(kuò)展是開放的

為什么要對功能擴(kuò)展開放呢?

對于任何一個程序來說,不可能在設(shè)計(jì)之初就已經(jīng)想好了所有的功能并且未來不做任何更新和修改。所以我們必須允許后來擴(kuò)展、添加新功能。

2.對修改是封閉的

 為什么要對修改封閉呢?

就像我們剛剛提到的,因?yàn)槲覀儗懙囊粋€函數(shù),很有可能在其他地方已經(jīng)被導(dǎo)入使用了,如果這個時候我們對其進(jìn)行了修改,很有可能影響其他已經(jīng)正在使用該函數(shù)的代碼。

裝飾器就完美遵循了這個開放封閉原則。這就是學(xué)裝飾器的初衷



小結(jié):

  • 1、裝飾器的固定格式(模板)

#格式一

def timer(func):
    def inner(*args,**kwargs):
        '''執(zhí)行函數(shù)之前要做的'''
        re = func(*args,**kwargs)
        '''執(zhí)行函數(shù)之后要做的'''
        return re
    return inner

#格式二

from functools import wraps

def deco(func):
    @wraps(func) #加在最內(nèi)層函數(shù)正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

關(guān)于“Python裝飾器函數(shù)怎么使用”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“Python裝飾器函數(shù)怎么使用”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)頁名稱:Python裝飾器函數(shù)怎么使用
URL鏈接:http://muchs.cn/article40/pidsho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)網(wǎng)站排名、靜態(tài)網(wǎng)站、商城網(wǎng)站外貿(mào)網(wǎng)站建設(shè)、微信小程序

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設(shè)計(jì)公司