學習python時,我提出過如下問題:
1.裝飾器是什麼?
2.乙個@符號 + 乙個函式名就是乙個裝飾器了?
3.什麼時候要用到這是神器的工具?
到底怎麼理解、怎麼應用裝飾器,在本文中概括一下自己的理解。
一、先舉栗子,逐層分析
1 # 獲取func函式的執行時間
2 import time
3 4 # 這是乙個計時函式
5 def deco(func): # 傳入乙個函式引數
6 starttime = time.time()
7 func()
8 endtime = time.time()
9 ms = (endtime - starttime)*1000
10 print("time is {} ms".format(ms))
11
12 def func():
13 print("hello")
14 time.sleep(1)
15 print("decorator")
16
17 deco(f)
上面的**裡 deco 就是 func 的裝飾函式,func 被當作乙個引數傳入 deco 方法中,返回deco裡的返回值。
這就是乙個裝飾器的功能,不影響源**,通過裝飾器來實現需求的功能。這是我自己的理解,下面有更專業的解釋。
所以,這裡回答了第 1 問,裝飾器到底是什麼?
本質上,裝飾器(decorator)就是乙個返回函式的高階函式,再本質的,裝飾器其實就是乙個閉包,把乙個函式當做引數然後返回乙個替代版函式。
python裡的閉包:python支援乙個叫做函式閉包的特性,用人話來講就是,巢狀定義在非全域性作用域裡面的函式能夠記住它在被定義的時候它所處的封閉命名空間。-- 摘自「12步輕鬆搞定裝飾器」
下面通過**示例說明本質上的裝飾器:
1 # 還是上面的例子,這裡進行改進
2 import time
3 4 def deco(func):
6 starttime = time.time()
7 func()
8 endtime = time.time()
9 ms = (endtime - starttime)*1000
10 print("time is {} ms".format(ms))
12 13 @deco
14 def func():
15 print("hello")
16 time.sleep(1)
17 print("decorator")
18 19 func()
很明顯,『裝飾』的方法不同,上一例用 deco 呼叫 func,本例直接呼叫 func 函式,返回結果一樣,但是返回值並不相同,乙個返回函式內部引數值,乙個返回函式。
二、乙個@符號 + 乙個函式名就是乙個裝飾器了?
python2.4支援使用識別符號@將裝飾器應用在函式上,只需要在函式的定義前加上@和裝飾器的名稱。只是加了一些語法糖讓裝飾的行為更加的簡潔明確和優雅一點。
其實它本來的樣子可以是這樣:
1 # 還是上面的例子,這裡進行改進
2 import time
3 4 def deco(func):
6 starttime = time.time()
7 func()
8 endtime = time.time()
9 ms = (endtime - starttime)*1000
10 print("time is {} ms".format(ms))
12 13 def func():
14 print("hello")
15 time.sleep(1)
16 print("decorator")
17 18 func = deco(func)
19 func()
是不是還是上面的簡潔明瞭一點,當然了這只是裝飾器寫法上的差別,只要理解了本質,就不用被 』@識別符號』 蒙住。
三、什麼時候要用到這神奇的工具?還有什麼花裡胡哨的用法?
坦率的講,我在目前的程式設計中並未使用過裝飾器,只是在閱讀**的時候見到,既然這麼頻繁的出現,說明必有大用。以後如有具體的專案實踐,我再來更新。
說是花裡胡哨的用法,其實就是它神奇的引數傳遞,我相信,這就是它經常被使用的原因之一,結合閉包的功能的理解,就會發現其神奇之處。
**來說事:
1 import time
2 3 def deco(func):
5 starttime = time.time()
6 func(a, b)
7 endtime = time.time()
8 ms = (endtime - starttime)*1000
9 print("time is {} ms".format(ms))
11 12
13 @deco
14 def func(a, b): # 要裝飾的函式需要傳入引數
15 print("hello,here is a func for add :")
16 time.sleep(1)
17 print("result is {}".format(a+b))
1819 func(2, 3)
1、當它被用作多個函式的裝飾器的時候,不確定其引數個數的多少,還可以用 python 的可變引數來定義,如下:
1 # 裝飾多個函式
2 import time
3 4 def deco(func):
6 starttime = time.time()
7 func(*args, **kwargs)
8 endtime = time.time()
9 ms = (endtime - starttime)*1000
10 print("time is {} ms".format(ms))
12 13 @deco
14 def func1(a,b):
15 print("hello,here is a func for add :")
16 time.sleep(1)
17 print("result is {}".format(a+b))
18 19 @deco
20 def func2(a,b,c):
21 print("hello,here is a func for add :")
22 time.sleep(1)
23 print("result is {}".format(a+b+c))
24 25 func1(1, 2)
26 func2(1, 2, 3)
2、應用多個裝飾器,實現多個功能,通過以下例子理解它的實現過程(本例項通過 ipython 實現,直接複製貼上出來的):
in [17]: import time
...:
...: def deco1(func):
...: print("i am deco1")
...: starttime = time.time()
...: func(*args, **kwargs)
...: endtime = time.time()
...: ms = (endtime - starttime)*1000
...: print("time is {} ms".format(ms))
...: print("deco1 is done")
...:
...: def deco2(func):
...: print("i am deco2")
...: func(*args, **kwargs)
...: print("deco2 is done")
...:
...: @deco01
...: @deco02
...: def func(a,b):
...: print("here is a + b:")
...: time.sleep(1)
...: print("result is {}".format(a+b))
...:
in [18]: func(1, 2)
i am deco1
i am deco2
here is a + b:
result is 3
deco2 is done
time is 1004 ms
deco1 is done
總結本例:多個裝飾器時,先呼叫第乙個 deco,再呼叫第二個 deco,後呼叫函式自己,再依次退出(先函式自己,再第二個deco,最後第乙個deco)。
總結:
12步輕鬆搞定python裝飾器
python的位置引數、預設引數等的區別
Python基礎學習(裝飾器)
增強乙個函式的功能,但又不想修改函式的定義,這種在 執行期間動態增加功能的方式,稱之為裝飾器。def log func def args,kw print callback format func.name return func args,kw log defnow print 2019 3 21...
Python基礎學習 函式裝飾器
裝飾器是python中非常實用的函式表達法,盡頭我們不講裝飾器原理,只講怎麼應用。裝飾器原理涉及物件導向以及函式本身也可以作為乙個引數被傳遞,原理比較簡單,但由於迴圈巢狀初學者難以理解。既然難以理解,那就先學會怎麼用,有了經驗,理解起來就相對容易了。首先我們要明白,裝飾器內函式是先於被裝飾函式執行的...
python基礎 裝飾器
裝飾器本質就是函式,功能是為其他函式新增附加功能。原則 不修改被修飾函式的源 不修改被修飾函式的呼叫方式 裝飾器的知識儲備 裝飾器 高階函式 函式巢狀 閉包 import time 定義乙個裝飾器計算函式執行時間 def timer func start time time.time res fun...