日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

python3装饰器的高级使用

發(fā)布時(shí)間:2025/10/17 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python3装饰器的高级使用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

對(duì)于需要重復(fù)計(jì)算子問題的情況,可以使用緩存,緩存實(shí)現(xiàn)有兩種方式:1.在函數(shù)內(nèi)定義某種數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)數(shù)據(jù) 2.使用裝飾器(閉包結(jié)構(gòu))

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

以菲波那切數(shù)列為例

1、一般的實(shí)現(xiàn)方式為:

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

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

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

#方法一:緩存法 #cache以值None層層傳遞到最底層,然后創(chuàng)建空字典 #cache逐層傳遞引用,每層的變量cache均指向同一對(duì)象! 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))

這種儲(chǔ)存中間值的方法不太直觀

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

#方法二:使用裝飾器,一來不改變函數(shù)形式,二可利用閉包保存變量狀態(tài),比緩存法容易理解 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))

裝飾器中閉包的典型使用場(chǎng)景

#practice27:函數(shù)元數(shù)據(jù)與裝飾器

1、 函數(shù)元數(shù)據(jù)

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

2、 使用裝飾器后函數(shù)如何保留元數(shù)據(jù)?

  • 被裝飾后的函數(shù),其元數(shù)據(jù)改為了wrapper函數(shù)!
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__)

  • 手動(dòng)修改元數(shù)據(jù)
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函數(shù)與常量
from functools import update_wrapper,WRAPPER_ASSIGNMENTS,WRAPPER_UPDATESdef deco(func):def wrapper(*args,**kargs):'''function wrapper'''print("in wrapper")func(*args,**kargs)#使用函數(shù)update_wrapper更改被裝飾后的函數(shù)wrapper的元數(shù)據(jù)#參數(shù)1:裝飾后的函數(shù);參數(shù)2:被裝飾函數(shù);參數(shù)3:指定替換哪些元數(shù)據(jù);參數(shù)4:指定合并哪些元數(shù)據(jù)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__) #這兩個(gè)常量皆為元組,一般情況下就使用這兩個(gè)常量作為update_wrapper的實(shí)參 print(WRAPPER_ASSIGNMENTS,WRAPPER_UPDATES)
  • 使用functools中的wraps裝飾器(帶參數(shù))
from functools import wrapsdef deco(func):#帶參數(shù)裝飾器,指定被裝飾的函數(shù),替換的元數(shù)據(jù)任然為WRAPPER_ASSIGNMENTS,WRAPPER_UPDATES#效果同上一種方法,不過更簡(jiǎn)潔@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:帶參數(shù)裝飾器

1、示例:實(shí)現(xiàn)函數(shù)參數(shù)類型檢查

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))

裝飾器的參數(shù)最終還是要使用在wrapper內(nèi)!

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

  • 實(shí)現(xiàn)函數(shù)運(yùn)行時(shí)間檢查
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會(huì)一直向上查找nonlocal shresholdshreshold = new_shreshold#定義裝飾器(本質(zhì)是函數(shù))的可變屬性,該屬性為一個(gè)函數(shù)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()#經(jīng)過裝飾器裝飾后的函數(shù)f1本質(zhì)上已經(jīng)成為wrapper;所以下面是在調(diào)用f1的屬性罷了f1.setTimeout1(2.5)for _ in range(10):f1()

溫習(xí)一下函數(shù)作為一等對(duì)象如何定義屬性!

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。