中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

python裝飾器原理與用法深入詳解

發布時間:2020-09-21 07:51:34 來源:腳本之家 閱讀:157 作者:nudt_qxx 欄目:開發技術

本文實例講述了python裝飾器原理與用法。分享給大家供大家參考,具體如下:

你會Python嘛?
我會!
那你給我講下Python裝飾器吧!
Python裝飾器啊?我沒用過哎

以上是我一個哥們面試時候發生的真實對白。

----------------------------------------------分割線------------------------------------------------------------------------------

簡言之,python裝飾器就是用于拓展原來函數功能的一種函數,這個函數的特殊之處在于它的返回值也是一個函數,使用python裝飾器的好處就是在不用更改原函數的代碼前提下給函數增加新的功能。
一般而言,我們要想拓展原來函數代碼,最直接的辦法就是侵入代碼里面修改,例如:

import time
def func():
  print("hello")
  time.sleep(1)
  print("world")

這是我們最原始的的一個函數,然后我們試圖記錄下這個函數執行的總時間,那最簡單的做法就是:

#原始侵入,篡改原函數
import time
def func():
  startTime = time.time()
  print("hello")
  time.sleep(1)
  print("world")
  endTime = time.time()
  msecs = (endTime - startTime)*1000
  print("time is %d ms" %msecs)

但是如果你的Boss在公司里面和你說:“小祁,這段代碼是我們公司的核心代碼,你不能直接去改我們的核心代碼。”那該怎么辦呢,我們仿照裝飾器先自己試著寫一下:

#避免直接侵入原函數修改,但是生效需要再次執行函數
import time
def deco(func):
  startTime = time.time()
  func()
  endTime = time.time()
  msecs = (endTime - startTime)*1000
  print("time is %d ms" %msecs)
def func():
  print("hello")
  time.sleep(1)
  print("world")
if __name__ == '__main__':
  f = func
  deco(f)#只有把func()或者f()作為參數執行,新加入功能才會生效
  print("f.__name__ is",f.__name__)#f的name就是func

這里我們定義了一個函數deco,它的參數是一個函數,然后給這個函數嵌入了計時功能。然后你可以拍著胸脯對老板說,看吧,不用動你原來的代碼,我照樣拓展了它的函數功能。

然后你的老板有對你說:“小祁,我們公司核心代碼區域有一千萬個func()函數,從func01()到func1kw(),按你的方案,想要拓展這一千萬個函數功能,就是要執行一千萬次deco()函數,這可不行呀,我心疼我的機器。”

好了,你終于受夠你老板了,準備辭職了,然后你無意間聽到了裝飾器這個神器,突然發現能滿足你閆博士的要求了。

我們先實現一個最簡陋的裝飾器,不使用任何語法糖和高級語法,看看裝飾器最原始的面貌:

#既不需要侵入,也不需要函數重復執行
import time
def deco(func):
  def wrapper():
    startTime = time.time()
    func()
    endTime = time.time()
    msecs = (endTime - startTime)*1000
    print("time is %d ms" %msecs)
  return wrapper
@deco
def func():
  print("hello")
  time.sleep(1)
  print("world")
if __name__ == '__main__':
  f = func #這里f被賦值為func,執行f()就是執行func()
  f()

這里的deco函數就是最原始的裝飾器,它的參數是一個函數,然后返回值也是一個函數。其中作為參數的這個函數func()就在返回函數wrapper()的內部執行。然后在函數func()前面加上@deco,func()函數就相當于被注入了計時功能,現在只要調用func(),它就已經變身為“新的功能更多”的函數了。

所以這里裝飾器就像一個注入符號:有了它,拓展了原來函數的功能既不需要侵入函數內更改代碼,也不需要重復執行原函數。

#帶有參數的裝飾器
import time
def deco(func):
  def wrapper(a,b):
    startTime = time.time()
    func(a,b)
    endTime = time.time()
    msecs = (endTime - startTime)*1000
    print("time is %d ms" %msecs)
  return wrapper
@deco
def func(a,b):
  print("hello,here is a func for add :")
  time.sleep(1)
  print("result is %d" %(a+b))
if __name__ == '__main__':
  f = func
  f(3,4)
  #func()

然后你滿足了Boss的要求后,Boss又說:“小祁,我讓你拓展的函數好多可是有參數的呀,有的參數還是個數不定的那種,你的裝飾器搞的定不?”然后你嘿嘿一笑,深藏功與名!

#帶有不定參數的裝飾器
import time
def deco(func):
  def wrapper(*args, **kwargs):
    startTime = time.time()
    func(*args, **kwargs)
    endTime = time.time()
    msecs = (endTime - startTime)*1000
    print("time is %d ms" %msecs)
  return wrapper
@deco
def func(a,b):
  print("hello,here is a func for add :")
  time.sleep(1)
  print("result is %d" %(a+b))
@deco
def func2(a,b,c):
  print("hello,here is a func for add :")
  time.sleep(1)
  print("result is %d" %(a+b+c))
if __name__ == '__main__':
  f = func
  func2(3,4,5)
  f(3,4)
  #func()

最后,你的老板說:“可以的,小祁,我這里一個函數需要加入很多功能,一個裝飾器怕是搞不定,裝飾器能支持多個嘛"

最后你就把這段代碼丟給了他:

#多個裝飾器
import time
def deco01(func):
  def wrapper(*args, **kwargs):
    print("this is deco01")
    startTime = time.time()
    func(*args, **kwargs)
    endTime = time.time()
    msecs = (endTime - startTime)*1000
    print("time is %d ms" %msecs)
    print("deco01 end here")
  return wrapper
def deco02(func):
  def wrapper(*args, **kwargs):
    print("this is deco02")
    func(*args, **kwargs)
    print("deco02 end here")
  return wrapper
@deco01
@deco02
def func(a,b):
  print("hello,here is a func for add :")
  time.sleep(1)
  print("result is %d" %(a+b))
if __name__ == '__main__':
  f = func
  f(3,4)
  #func()
'''
this is deco01
this is deco02
hello,here is a func for add :
result is 7
deco02 end here
time is 1003 ms
deco01 end here
'''

多個裝飾器執行的順序就是從最后一個裝飾器開始,執行到第一個裝飾器,再執行函數本身。

盜用評論里面一位童鞋的例子:

def dec1(func):
  print("1111")
  def one():
    print("2222")
    func()
    print("3333")
  return one
def dec2(func):
  print("aaaa")
  def two():
    print("bbbb")
    func()
    print("cccc")
  return two
@dec1
@dec2
def test():
  print("test test")
test()

輸出:

aaaa
1111
2222
bbbb
test test
cccc
3333

裝飾器的外函數和內函數之間的語句是沒有裝飾到目標函數上的,而是在裝載裝飾器時的附加操作。

17~20行是裝載裝飾器的過程,相當于執行了test=dect1(dect2(test)),此時先執行dect2(test),結果是輸出aaaa、將func指向函數test、并返回函數two,然后執行dect1(two),結果是輸出1111、將func指向函數two、并返回函數one,然后進行賦值。

用函數替代了函數名test。 22行則是實際調用被裝載的函數,這時實際上執行的是函數one,運行到func()時執行函數two,再運行到func()時執行未修飾的函數test。

更多關于Python相關內容感興趣的讀者可查看本站專題:《Python面向對象程序設計入門與進階教程》、《Python數據結構與算法教程》、《Python函數使用技巧總結》、《Python字符串操作技巧匯總》、《Python編碼操作技巧總結》及《Python入門與進階經典教程》

希望本文所述對大家Python程序設計有所幫助。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

临清市| 洞头县| 韶山市| 集贤县| 静乐县| 宝丰县| 五大连池市| 双峰县| 鄄城县| 丰镇市| 犍为县| 徐州市| 高尔夫| 普宁市| 沁水县| 晋宁县| 锡林浩特市| 山丹县| 临泉县| 孝感市| 波密县| 曲周县| 樟树市| 商水县| 白朗县| 宜宾县| 揭西县| 琼海市| 娄底市| 崇仁县| 平遥县| 农安县| 怀来县| 巴楚县| 平南县| 新乡县| 莫力| 织金县| 广水市| 平谷区| 揭阳市|