Python學習之路6 裝飾器

2022-06-23 06:54:12 字數 4270 閱讀 9500

定義:本質是函式,(裝飾其他函式)就是為其他函式新增附加功能。

原則:1.不能修改被裝飾的函式的源**

2.不能修改被裝飾的函式的呼叫方式

實現裝飾器的知識儲備:

1.函式即「變數」

2.高階函式(滿足下列條件之一就是高階函式)

3.巢狀函式

總結:

高階函式+巢狀函式=>裝飾器

def bar():  #這裡定義個函式

print('this is bar...')

func = bar #將函式當變數一樣賦值給func

func() #這是func加上()就可以當函式用了

這就是函式即變數。

a:把乙個函式名當做形參傳給另一函式(在不修改被裝飾函式源**的情況下修改其他功能,但是呼叫方式變了)

def bar():

print('this is bar...')

bar()

print('----------------------------------')

def test(func): #在這裡增加了功能

print(func)

test(bar) #但是這裡修改了呼叫方式

b:返回值中包含函式名(不修改函式的呼叫方式,而修改函式功能)

def bar():

print('this is bar...')

bar()

print('----------------------------------')

def test(func): #在這裡增加了功能

print(func)

return func #這裡返回了函式位址

bar = test(bar) #將函式位址賦給乙個變數,該變數和傳入函式同名

bar() #這個變數加上括號,就可以當函式用了,同時又沒有修改函式的呼叫方式

x = 1

def test1():

def test2():

def test3():

x = 3

print(x)

test3()

test2()

test1()

像這樣在乙個函式裡面定義乙個函式就叫做巢狀函式。

現在三個知識點都已經解釋過了,下面先實現乙個原始版的裝飾器。

原始版裝飾器

import time

def test1(): #這裡是被裝飾的函式

time.sleep(1)

print("this is test1....")

def timer(func): #這裡是裝飾器函式

def deco():

strat = time.time()

func()

stop = time.time()

print("run time %s" %(stop-strat))

return deco

test1 = timer(test1)

test1()

這個裝飾器的功能是測試test1函式的執行時間,deco函式有這個功能,所以這裡其實我想執行的是deco函式,timer()函式的返回值也就是deco函式的位址;同時deco函式想要執行也要滿足另乙個條件,那就是需要呼叫timer函式,只有當timer函式執行的時候timer函式裡面寫的那些東西才會生效或者說被啟用,deco函式才會定義成功。到此,test=timer(test1)這句**的意思就是,先呼叫timer函式讓deco函式的定義生效,同時將要被裝飾的函式test1函式的位址傳入,讓deco函式裡面的func函式生效,這是timer函式又會將deco函式的位址返回,並將位址賦值給test1這個變數。然後下面的test1後面加上括號,變成test1()的形式,就可以執行了。這樣乙個原始版的裝飾器就寫完了。

接下來要寫乙個真實裝飾器的例項

import time

def timer(func):

def deco():

start_time = time.time()

func()

stop_time = time.time()

print('the func run time is %s' %(stop_time-start_time))

return deco

@timer #這裡等於 test = timer(test),要裝飾哪個函式,就在哪個函式前面加上這個

def test():

time.sleep(2)

print('this is test...')

test()

上面這些都是一些比較基本的,如果裝飾有引數的函式且引數的個數還都不一定怎麼辦呢?下面寫乙個高階案例 -- 有引數的裝飾器

高階案例 -- 有引數裝飾器

import time

def timer(func):

def deco(*args,**kwargs):  #在這裡接收引數

start_time = time.time()

func(*args,**kwargs)

stop_time = time.time()

print('the func run time is %s' %(stop_time-start_time))

return deco

@timer

def test(name):

time.sleep(2)

print('this is test...',name)

test('vector')

如果原test函式裡面有返回值,被裝飾後我們列印它print(test()),結果會是none。因為這時的test=deco,而deco沒有返回值,所以列印不出來。這樣就會出現乙個問題,如果test函式有返回值,test函式的乙個功能(返回值)就會被弄丟了。

解決辦法看下面案例。

高高階案例 -- 有返回值的裝飾器

import time

def timer(func):

def deco(*args,**kwargs):

start_time = time.time()

res = func(*args,**kwargs)

stop_time = time.time()

print('the func run time is %s' %(stop_time-start_time))

return res #這裡將func的返回值返回

return deco

@timer

def test(name):

time.sleep(2)

print('this is test...',name)

return 'asdfasdfgdfgd'

print(test('vector'))

這樣就可以列印出返回值了。

還有些時候我們需要給裝飾器進行傳參,給內部使用。解決方案看下面。

高高高階案例 -- 給裝飾器傳參

import time

def timer(temp):

print('this is ',temp) #這裡是加進來的引數

def out(func):

def deco(*args,**kwargs):

start_time = time.time()

res = func(*args,**kwargs)

stop_time = time.time()

print('the func run time is %s' %(stop_time-start_time))

return res

return deco

return out

@timer('temp')

def test(name):

time.sleep(2)

print('this is test...',name)

return 'asdfasdfgdfgd'

print(test('vector'))

實際上就是整體又在外面加了一層內嵌函式。

Python學習之路 裝飾器(1)

裝飾器本身是利用閉包實現的,因此只有真正學會了閉包中的知識點才能完全理解裝飾器的語法。試想乙個問題 在乙個工程中有乙個函式func 現在有乙個需求是func 現在本身不能滿足的,因此需要重新實現func 的功能。這是正常的思路,也是可行的,但是卻違背了開發中的 開放 封閉 原則。封閉 函式本身的功能...

Python學習之路 裝飾器(2)

coding utf 8 def f1 func print in f1 def f1 inner print in f1 inner func return f1 inner def f2 func print in f2 def f2 inner print in f2 inner func r...

Python學習之路 裝飾器(3)

上兩篇提到的裝飾器的例子中,被修飾的函式沒有引數,那麼如果修飾帶引數的裝飾器又該如何書寫呢?coding utf 8 def f1 func print in f1 def f1 inner print in f1 inner func return f1 inner f1def f a,b pri...