欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解如何利用Python裝飾器優(yōu)化代碼

 更新時間:2023年05月09日 09:13:34   作者:簡說Python  
這篇文章主要帶大家深入探討裝飾器的應(yīng)用,包括計(jì)時器裝飾器和緩存裝飾器等的實(shí)現(xiàn),文中的示例代碼講解詳細(xì),需要的小伙伴可以參考下

本文將帶你深入探討裝飾器的應(yīng)用,包括計(jì)時器裝飾器和緩存裝飾器等的實(shí)現(xiàn)。通過這些案例,我們可以看到裝飾器的強(qiáng)大和靈活,它們可以幫助我們優(yōu)化代碼,提高性能,讓我們的程序更加健壯和高效。

你是不是經(jīng)常發(fā)現(xiàn)自己寫 Python 代碼很冗余?或者已經(jīng)寫了一些簡潔的代碼,但是正常運(yùn)行時卻會遇到性能問題?那么,Python 裝飾器就是你的救星!本文將帶你深入探討裝飾器的應(yīng)用,包括計(jì)時器裝飾器和緩存裝飾器的實(shí)現(xiàn)。

什么是裝飾器

先來了解一下什么是裝飾器。

裝飾器是 Python 的一個重要特性,它允許你將一個函數(shù)作為參數(shù)傳遞給另一個函數(shù),并返回一個新的函數(shù),而不對原始函數(shù)進(jìn)行修改。這使得你可以在不改變代碼本身的情況下,動態(tài)地修改函數(shù)的行為。下面我們會通過具體的案例來進(jìn)一步解釋這個概念。

裝飾器的應(yīng)用

直接通過案例來理解和使用裝飾器。

計(jì)時器裝飾器

計(jì)時器裝飾器可以幫助你在代碼運(yùn)行時自動計(jì)時,以便你了解代碼的性能。下面是一個例子:

import?time

#?定義計(jì)時器裝飾器
def?timer_decorator(func):
????#?定義內(nèi)部包裝函數(shù),用于接收任意數(shù)量的位置參數(shù)和關(guān)鍵字參數(shù)
????def?wrapper(*args,?**kwargs):
????????#?記錄函數(shù)運(yùn)行開始時間
????????start_time?=?time.time()
????????#?調(diào)用原始函數(shù)并將結(jié)果存儲在result中
????????result?=?func(*args,?**kwargs)
????????#?記錄函數(shù)運(yùn)行結(jié)束時間
????????end_time?=?time.time()
????????#?計(jì)算函數(shù)運(yùn)行時間并打印結(jié)果
????????print(f"函數(shù)?{func.__name__}?運(yùn)行時間為?{end_time?-?start_time}?秒")
????????#?返回原始函數(shù)的結(jié)果
????????return?result
????#?返回包裝函數(shù)
????return?wrapper

@timer_decorator
def?slow_function():
????time.sleep(2)
????print("使用?timer_decorator?計(jì)算下?slow_function?函數(shù)的運(yùn)行時長")

slow_function()

在上面的例子中,我們定義了一個計(jì)時器裝飾器 timer_decorator,并將它應(yīng)用到一個簡單函數(shù) slow_function 上。當(dāng)我們調(diào)用 slow_function 時,計(jì)時器會自動開始計(jì)時,并在函數(shù)執(zhí)行完畢后輸出函數(shù)的運(yùn)行時間。

緩存裝飾器

緩存裝飾器可以幫助你避免重復(fù)計(jì)算,以提高代碼的性能。下面是一個例子,使用了一個緩存裝飾器來優(yōu)化遞歸斐波那契數(shù)列計(jì)算:

#?定義緩存裝飾器
def?cache_decorator(func):
????#?創(chuàng)建一個字典來存儲緩存的結(jié)果
????cache?=?dict()
????#?定義內(nèi)部包裝函數(shù),用于接收任意數(shù)量的位置參數(shù)
????def?wrapper(*args):
????????#?檢查當(dāng)前參數(shù)是否在緩存中
????????if?args?in?cache:
????????????#?如果在緩存中,則從緩存中獲取結(jié)果并打印提示信息
????????????print(f"從緩存中獲取?{args}?的結(jié)果")
????????????return?cache[args]
????????#?如果不在緩存中,則調(diào)用原始函數(shù)計(jì)算結(jié)果
????????result?=?func(*args)
????????#?將計(jì)算結(jié)果存儲到緩存中,并打印提示信息
????????cache[args]?=?result
????????print(f"計(jì)算?{args}?的結(jié)果并將其存入緩存")
????????#?返回計(jì)算結(jié)果
????????return?result
????#?返回包裝函數(shù)
????return?wrapper
#?使用緩存裝飾器修飾fibonacci函數(shù)
@cache_decorator
def?fibonacci(n):
????if?n?<?2:
????????return?n
????else:
????????return?fibonacci(n-1)?+?fibonacci(n-2)
print(fibonacci(3))
print("*****************")
print(fibonacci(5))

在上面的例子中,我們定義了一個緩存裝飾器 cache_decorator,并將它應(yīng)用到一個計(jì)算斐波那契數(shù)列的函數(shù) fibonacci 上。當(dāng)我們多次調(diào)用 fibonacci 函數(shù)時,緩存裝飾器會自動檢查緩存中是否已經(jīng)計(jì)算了該值,如果已經(jīng)計(jì)算則直接返回緩存中的值,否則進(jìn)行計(jì)算并將結(jié)果存入緩存。

類型檢查裝飾器

類型檢查裝飾器可以幫助你在函數(shù)調(diào)用時自動檢查參數(shù)類型,以便你避免傳入錯誤的參數(shù)。下面是一個例子:

#?定義類型檢查裝飾器
def?type_check_decorator(func):
????#?定義內(nèi)部包裝函數(shù),用于接收任意數(shù)量的位置參數(shù)和關(guān)鍵字參數(shù)
????def?wrapper(*args,?**kwargs):
????????#?遍歷位置參數(shù)
????????for?i,?arg?in?enumerate(args):
????????????#?如果參數(shù)不是字符串類型,拋出TypeError異常
????????????if?not?isinstance(arg,?str):
????????????????raise?TypeError(f"第?{i+1}?個參數(shù)值?{arg}?必須是?str?類型")
????????#?遍歷關(guān)鍵字參數(shù)
????????for?key,?value?in?kwargs.items():
????????????#?如果關(guān)鍵字參數(shù)的值不是字符串類型,拋出TypeError異常
????????????if?not?isinstance(value,?str):
????????????????raise?TypeError(f"關(guān)鍵字參數(shù)?{key}?必須是?str?類型")
????????#?參數(shù)檢查通過后,調(diào)用原始函數(shù)并返回結(jié)果
????????return?func(*args,?**kwargs)
????#?返回包裝函數(shù)
????return?wrapper
#?使用類型檢查裝飾器修飾concat_strings函數(shù)
@type_check_decorator
def?concat_strings(*strings,?sep="?"):
????return?sep.join(strings)

在上面的例子中,我們定義了一個類型檢查裝飾器 type_check_decorator,并將它應(yīng)用到一個將多個字符串拼接為一個字符串的函數(shù) concat_strings 上。當(dāng)我們調(diào)用 concat_strings 時,類型檢查裝飾器會自動檢查參數(shù)類型,并在參數(shù)類型錯誤時拋出異常。

日志裝飾器

日志裝飾器可以幫助你在代碼執(zhí)行時自動記錄日志,以便你了解代碼的執(zhí)行情況。下面是一個例子:

import?logging
#?定義日志裝飾器
def?log_decorator(func):
????#?配置日志記錄器,將日志記錄到文件example.log,日志級別為INFO
????logging.basicConfig(filename="example.log",?level=logging.INFO)
????#?定義內(nèi)部包裝函數(shù),用于接收任意數(shù)量的位置參數(shù)和關(guān)鍵字參數(shù)
????def?wrapper(*args,?**kwargs):
????????#?記錄函數(shù)調(diào)用信息到日志文件中
????????logging.info(f"Calling?function?{func.__name__}")
????????#?調(diào)用原始函數(shù)并將結(jié)果存儲在result中
????????result?=?func(*args,?**kwargs)
????????#?記錄函數(shù)返回值信息到日志文件中
????????logging.info(f"Function?{func.__name__}?returned?{result}")
????????#?返回原始函數(shù)的結(jié)果
????????return?result
????#?返回包裝函數(shù)
????return?wrapper
#?使用日志裝飾器修飾add函數(shù)
@log_decorator
def?add(a,?b):
????return?a?+?b
#?調(diào)用add函數(shù)并打印結(jié)果
print(add(1,?2))

在上面的例子中,我們定義了一個日志裝飾器 log_decorator,并將它應(yīng)用到一個加法函數(shù) add 上。當(dāng)我們調(diào)用 add 時,日志裝飾器會自動記錄日志,并將日志信息寫入到指定的文件中。

授權(quán)裝飾器

授權(quán)裝飾器可以幫助你在函數(shù)調(diào)用時自動檢查用戶權(quán)限,以便你避免未授權(quán)的用戶訪問敏感數(shù)據(jù)。下面是一個例子:

#?定義一個高階函數(shù),接受一個所需角色列表作為參數(shù)
def?roles_required(required_roles):
????#?定義授權(quán)裝飾器
????def?authorization_decorator(func):
????????#?定義包裝函數(shù),用于接收任意數(shù)量的位置參數(shù)和關(guān)鍵字參數(shù)
????????def?wrapper(*args,?**kwargs):
????????????#?獲取用戶角色,默認(rèn)為"guest"
????????????user_role?=?kwargs.get("user_role",?"guest")
????????????#?檢查用戶角色是否在所需角色列表中
????????????if?user_role?not?in?required_roles:
????????????????#?如果不在列表中,拋出一個?PermissionError?異常
????????????????raise?PermissionError(f"訪問被拒絕:?需要?{',?'.join(required_roles)}?其中之一的角色")
????????????#?如果用戶角色在所需角色列表中,調(diào)用原始函數(shù)并返回結(jié)果
????????????return?func(*args,?**kwargs)
????????#?返回包裝函數(shù)
????????return?wrapper
????#?返回授權(quán)裝飾器
????return?authorization_decorator
#?使用?roles_required?裝飾器,允許?admin?和?user?角色的用戶訪問受保護(hù)的功能
@roles_required(["admin",?"user"])
def?protected_function(user_role="guest"):
????print("受保護(hù)的功能已成功執(zhí)行")
#?嘗試使用?guest?角色訪問受保護(hù)的功能
try:
????protected_function(user_role="guest")
except?PermissionError?as?e:
????print(e)
#?嘗試使用?user?角色訪問受保護(hù)的功能
try:
????protected_function(user_role="user")
except?PermissionError?as?e:
????print(e)
#?嘗試使用?admin?角色訪問受保護(hù)的功能
try:
????protected_function(user_role="admin")
except?PermissionError?as?e:
????print(e)

在上面的例子中,我們首先定義了一個名為roles_required的高階函數(shù),它接受一個required_roles列表參數(shù)。該高階函數(shù)返回一個名為authorization_decorator的裝飾器,該裝飾器定義了一個名為wrapper的內(nèi)部函數(shù),用于檢查用戶角色是否在所需角色列表中。如果用戶角色在列表中,裝飾器將調(diào)用原始函數(shù)并返回結(jié)果;否則,它將拋出一個PermissionError異常。

我們使用@roles_required(["admin", "user"])裝飾器來修飾protected_function,確保只有具有admin或user角色的用戶可以訪問該功能。然后,我們嘗試使用不同角色的用戶訪問受保護(hù)的功能,以驗(yàn)證裝飾器的功能。

拓展

在上面的案例中,我們用到了兩個額外功能:高階函數(shù)和包裝器。這兩個概念在Python裝飾器的實(shí)現(xiàn)中起到了關(guān)鍵作用。接下來,我們詳細(xì)介紹它們的作用和應(yīng)用:

高階函數(shù)

高階函數(shù)是指接收一個或多個函數(shù)作為參數(shù)并返回一個新函數(shù)的函數(shù)。在我們的示例中,roles_required函數(shù)是一個高階函數(shù)。它接收一個所需角色列表作為參數(shù),并返回一個名為authorization_decorator的裝飾器函數(shù)。

高階函數(shù)在函數(shù)式編程中具有重要作用,因?yàn)樗鼈冊试S我們將函數(shù)作為參數(shù)傳遞,從而提高代碼的靈活性和復(fù)用性。

高階函數(shù)的應(yīng)用:

  • 實(shí)現(xiàn)代碼復(fù)用和模塊化
  • 簡化代碼結(jié)構(gòu),提高代碼可讀性
  • 實(shí)現(xiàn)函數(shù)式編程范式,支持函數(shù)作為參數(shù)傳遞和返回值

包裝器

包裝器(Wrapper)是一個用于修改其他函數(shù)行為的函數(shù)。在我們的示例中,wrapper函數(shù)是一個包裝器。它接收任意數(shù)量的位置參數(shù)和關(guān)鍵字參數(shù),然后根據(jù)特定邏輯(在這個例子中是檢查用戶角色)來決定是否調(diào)用原始函數(shù)(即被裝飾的函數(shù))。

包裝器的應(yīng)用:

  • 修改或增強(qiáng)原始函數(shù)的行為,而無需修改原始函數(shù)的代碼
  • 實(shí)現(xiàn)代碼的解耦,將不同功能分開
  • 提高代碼的可讀性和可維護(hù)性

在裝飾器中,高階函數(shù)和包裝器共同發(fā)揮作用。高階函數(shù)負(fù)責(zé)接收參數(shù)并生成裝飾器,而裝飾器內(nèi)部的包裝器負(fù)責(zé)根據(jù)特定邏輯對原始函數(shù)進(jìn)行修改或增強(qiáng)。這種組合提供了一種靈活且強(qiáng)大的方式來擴(kuò)展和修改函數(shù)的行為,同時保持代碼的模塊化和易于維護(hù)。

總結(jié)

本文介紹了 Python 裝飾器的基本概念和幾種常見的應(yīng)用場景:計(jì)時器裝飾器和緩存裝飾器等。通過這些案例,我們可以看到裝飾器的強(qiáng)大和靈活,它們可以幫助我們優(yōu)化代碼,提高性能,讓我們的程序更加健壯和高效。

到此這篇關(guān)于詳解如何利用Python裝飾器優(yōu)化代碼的文章就介紹到這了,更多相關(guān)Python裝飾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論