日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python3装饰器的高级使用

發布時間:2025/10/17 python 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python3装饰器的高级使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

#practice26:緩存與裝飾器(遞歸子問題)

對于需要重復計算子問題的情況,可以使用緩存,緩存實現有兩種方式:1.在函數內定義某種數據結構存儲數據 2.使用裝飾器(閉包結構)

菲波那切數列為:1,1,2,3,5,8,13;即從第三項開始,每一項為前兩項之和。

以菲波那切數列為例

1、一般的實現方式為:

#求第n項的斐波那契數,從0開始 def fibonacci(n):if n <= 1:return 1return fibonacci(n-1) + fibonacci(n-2)print(fibonacci(33))

上述函數中由于需要重復計算某些項,所以計算速度非常緩慢,如果在計算過程中能保存一些中間值,速度提升非常明顯

2、使用緩存:保存中間值

#方法一:緩存法 #cache以值None層層傳遞到最底層,然后創建空字典 #cache逐層傳遞引用,每層的變量cache均指向同一對象! def fibonacci(n,cache=None):if cache is None:cache = {}if n in cache.keys():return cache[n]if n <= 1:return 1cache[n] = fibonacci(n-1,cache) + fibonacci(n-2,cache)return cache[n]print(fibonacci(33))

這種儲存中間值的方法不太直觀

3、 使用裝飾器,利用閉包保存中間值

#方法二:使用裝飾器,一來不改變函數形式,二可利用閉包保存變量狀態,比緩存法容易理解 def decorator(f):cache = {}def wrapper(*args,**kargs):if args not in cache.keys():cache[args] = f(*args,**kargs)return cache[args]return wrapper@decorator def fibonacci(n):if n <= 1:return 1return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(33))

裝飾器中閉包的典型使用場景

#practice27:函數元數據與裝飾器

1、 函數元數據

def f(key,a=1,b=[]):'''function f'''print(b)print(key*2) #函數名稱 print(f.__name__) #函數注釋 print(f.__doc__) #函數所屬模塊 print(f.__module__) #函數的默認參數元組 print(f.__defaults__) #修改函數參數的默認參數居然成功了,因為元組內包含列表,列表是可變對象! #正因如此,不應該把可變對象作為參數的默認值! f.__defaults__[1].append('100') f(1) ##會報錯,元組的元素不可被賦值 #f.__defaults__[0] = 10 #f(1)def func1():a = 3return lambda x: a*x g = func1() #讀取函數的閉包 #每個閉包包含多個cell對象 print(g.__closure__) #cell對象的cell_contents屬性可以讀取值 print(g.__closure__[0].cell_contents)

2、 使用裝飾器后函數如何保留元數據?

  • 被裝飾后的函數,其元數據改為了wrapper函數!
def deco(func):def wrapper(*args,**kargs):'''function wrapper'''print("in wrapper")func(*args,**kargs)return wrapperdef f1(n):'''function f1'''print(n**2)print(f1.__name__,f1.__doc__)@deco def f2(n):'''function f2'''print(n**2) print(f2.__name__,f2.__doc__)

  • 手動修改元數據
def deco(func):def wrapper(*args,**kargs):'''function wrapper'''print("in wrapper")func(*args,**kargs)wrapper.__name__ = func.__name__wrapper.__doc__ = func.__doc__return wrapperdef f1(n):'''function f1'''print(n**2)print(f1.__name__,f1.__doc__)@deco def f2(n):'''function f2'''print(n**2) print(f2.__name__,f2.__doc__)

  • 使用functools模塊中的update_wrapper函數與常量
from functools import update_wrapper,WRAPPER_ASSIGNMENTS,WRAPPER_UPDATESdef deco(func):def wrapper(*args,**kargs):'''function wrapper'''print("in wrapper")func(*args,**kargs)#使用函數update_wrapper更改被裝飾后的函數wrapper的元數據#參數1:裝飾后的函數;參數2:被裝飾函數;參數3:指定替換哪些元數據;參數4:指定合并哪些元數據update_wrapper(wrapper,func,WRAPPER_ASSIGNMENTS,WRAPPER_UPDATES)return wrapperdef f1(n):'''function f1'''print(n**2)print(f1.__name__,f1.__doc__)@deco def f2(n):'''function f2'''print(n**2) print(f2.__name__,f2.__doc__) #這兩個常量皆為元組,一般情況下就使用這兩個常量作為update_wrapper的實參 print(WRAPPER_ASSIGNMENTS,WRAPPER_UPDATES)
  • 使用functools中的wraps裝飾器(帶參數)
from functools import wrapsdef deco(func):#帶參數裝飾器,指定被裝飾的函數,替換的元數據任然為WRAPPER_ASSIGNMENTS,WRAPPER_UPDATES#效果同上一種方法,不過更簡潔@wraps(func)def wrapper(*args,**kargs):'''function wrapper'''print("in wrapper")func(*args,**kargs)return wrapperdef f1(n):'''function f1'''print(n**2)print(f1.__name__,f1.__doc__)@deco def f2(n):'''function f2'''print(n**2) print(f2.__name__,f2.__doc__)

此為推薦方法

#practice28:帶參數裝飾器

1、示例:實現函數參數類型檢查

def type(*types,**ktypes):def decorator(func):def wrapper(*args,**kargs):allmatch = Truefor value,_type in zip(args,types):if not isinstance(value,_type):print("value: " + str(value) + " is not " + str(_type))allmatch = Falsebreakif allmatch:func(*args,**kargs)return wrapperreturn decorator@type(int,str,int) def f1(a,b,c):print(a,b,c)@type(int,int,str,tuple) def f2(a,b,c,d):print(a,b,c,d)f1("s",'qq',55) f2(1,2,3,4) f2(1,2,"qq",(22,33))

裝飾器的參數最終還是要使用在wrapper內!

2、示例:屬性可修改的函數裝飾器

  • 實現函數運行時間檢查
import time from random import randint import loggingdef runtime(shreshold):def decorator(func):def wrapper(*args,**kargs):start = time.time()func(*args,**kargs)end = time.time()period = end - startif period > shreshold:msg = '%s:%s > %s' % (func.__name__,period,shreshold)logging.warn(msg)return wrapperreturn decorator@runtime(1.5) def f1():print("in test")while randint(0,1):time.sleep(5)for _ in range(30):f1()
  • 使裝飾器屬性可修改
import time from random import randint import loggingdef runtime(shreshold):def decorator(func):def wrapper(*args,**kargs):start = time.time()func(*args,**kargs)end = time.time()period = end - startif period > shreshold:msg = '%s:%s > %s' % (func.__name__,period,shreshold)logging.warn(msg)def setTimeout(new_shreshold):#nonlocal會一直向上查找nonlocal shresholdshreshold = new_shreshold#定義裝飾器(本質是函數)的可變屬性,該屬性為一個函數wrapper.setTimeout1 = setTimeoutreturn wrapperreturn decorator@runtime(1.5) def f1():print("in test")while randint(0,1):time.sleep(1)if __name__ == "__main__":for _ in range(10):f1()#經過裝飾器裝飾后的函數f1本質上已經成為wrapper;所以下面是在調用f1的屬性罷了f1.setTimeout1(2.5)for _ in range(10):f1()

溫習一下函數作為一等對象如何定義屬性!

總結

以上是生活随笔為你收集整理的python3装饰器的高级使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。