Python函数篇(5)-装饰器及实例讲解
1.裝飾器的概念
??裝飾器本質上就是一個函數,主要是為其他的函數添加附加的功能,裝飾器的原則有以下兩個:
- 裝飾器不能修改被修飾函數的源代碼
- 裝飾器不能修改被修改函數的調用方式
??裝飾器可以簡單的理解為:高階函數+嵌套函數+閉包
2.高階函數
??高階函數我在前面的博客中已經講過了,在這里我再簡單的說一下吧。
??高階函數:如果一個函數接收的參數是一個函數名,或者返回值是函數名,只要滿足任意一個條件,這個函數就稱為高階函數。
- 接收的參數是一個函數名
??在上面的例子中,我定義了兩個函數,foo()和bar(),在調用bar()函數的時候,我將foo()作為一個參數傳給了bar(),運行就會得到foo()的結果,這樣的函數就可以成為高階函數。
- 返回值是一個函數名
??調用bar()函數 返回的就是foo()的內存地址,這也可以稱為高階函數。
3.函數嵌套
??函數嵌套:函數嵌套我在前面也已經講過了,其實就是函數的內部再聲明函數,很好理解的一個概念,舉個例子:如下
def foo():print("the result from foo")def bar():print("the result from bar")bar() foo()??在上面這個例子中,我在函數foo()的內部又寫了一個bar()函數,并在下面調用了該函數,這種方式就叫做函數嵌套,可以嵌套很多層,只要注意函數縮進問題
4.閉包
??在Python中閉包的表現形式可以理解為:如果在一個內部函數里,對在外部作用域(但不是在全局作用域)的變量進行引用,那么內部函數就被認為是閉包(closure)。
??單從上面的定義可能很難理解,我下面用一個簡單的程序說明一下:
??在上面這個例子中,bar()就是foo()的一個內部函數,在bar()的局部作用于可以直接使用foo()的局部變量a,b,簡單的說,這種內部函數可以訪問外部函數變量的行為,就叫做閉包。
4.裝飾器實例
??為了能讓大家更好的理解裝飾器,我會分步做出這個實例。
- 裝飾器的基本實現
??先定義一個函數name(),3秒后打印名字
import time def name():time.sleep(2)print("my name is 尼古拉斯趙四") name()??現在有一個需求,我想要統計這個函數一個運行了多少秒,在不修改源代碼的情況下,就需要給這個函數寫一個裝飾器來完成這個需求。
def timmer(func): #定義一個形參,就是為了接受name()這個函數,注意前面文章就已經強調過的:函數即變量---func=namedef wapper(): #定義函數wapper(),用來接收name的參數start_time=time.time()func() #實質上就是在運行test() stop_time=time.time()print("name()函數一共運行了%s 秒"%(stop_time-start_time))return wapper import time @timmer #使用裝飾器的方法,通過@+作為裝飾器的那個函數名 def name():time.sleep(2)print("my name is 尼古拉斯趙四") name() 運行結果: my name is 尼古拉斯趙四 name()函數一共運行了2.0002381801605225 秒??上面這個例子就是一個簡單的裝飾器,沒有修改原函數的調用方法和返回值,裝飾器timmer中用到了高階函數+函數嵌套+閉包的知識,ok,完美。
- 在裝飾器中添加參數
??上面的例子是完美的實現了所需要的功能,但是問題來了,如果原函數是現在這樣呢?
??我需要隨機傳入兩個值,打印出他的姓名和年齡,如果原函數這樣調用,使用上面的裝飾器肯定會出錯,那就需要在裝飾器函數中做如下修改:def wapper(my_name,my_age)和func(my_name,my_age)這兩行加入相同的參數,也是可以的,但如果name函數我再修改呢,不傳入兩個參數了 ,傳3個 或更多,每次都要去修改豈不是很麻煩,這就需要做一些改變了 。
def timmer(func): def wapper(*args,**kwargs): #這里用*args,**kwargs代替,這樣 ,不管原函數傳入多少個參數,都可以匹配start_time=time.time()func(*args,**kwargs) #同樣,接受任意多個參數 (如果不懂這個什么意思,翻看我前面函數篇的博客,有講到)stop_time=time.time()print("name()函數一共運行了%s 秒"%(stop_time-start_time))return wapper- 裝飾器添加返回值
??參數問題解決了,下面我的原函數又變了
??在這個函數中,我需求是在運行完函數返回"尼古拉斯 你真年輕"這句話,還是用上面的裝飾器返回值會是my name is 尼古拉斯趙四,my age is 18 name()函數一共運行了2.000795364379883 秒 None,返回值是None而不是想要的結果,大家可以試一下,所以要加如下修改:
def timmer(func):def wapper(*args,**kwargs): start_time=time.time()res=func(*args,**kwargs) #將func()運行結果賦值給變量resstop_time=time.time()print("name()函數一共運行了%s 秒"%(stop_time-start_time))return res #返回res,其實就是在返回name()return wapper??上面就詳細寫了裝飾器的實現過程,就先寫到這,后續我會豐富裝飾器并做出一個通俗易懂的例子供大家參考,稍后一些時間也會發布在我的博客里,感興趣的到時候可以看一下,希望可以幫助大家對裝飾器有更好的理解。
轉載于:https://www.cnblogs.com/Chen-Zhipeng/p/8035938.html
總結
以上是生活随笔為你收集整理的Python函数篇(5)-装饰器及实例讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU2029:Palindromes
- 下一篇: scrapy爬虫,爬取图片