Python使用atexit模塊實(shí)現(xiàn)Golang的defer功能
在 Go 里面可以通過 defer 語句讓函數(shù)在結(jié)束時(shí)執(zhí)行預(yù)定義好的一些操作,舉個(gè)例子。
package main import "fmt" func main() { defer fmt.Println("高老師總能分享出好東西") fmt.Println("執(zhí)行結(jié)束") /* 執(zhí)行結(jié)束 高老師總能分享出好東西 */ }
這個(gè)功能非常方便,比如打開文件之后可以執(zhí)行 defer fp.Close(),這樣函數(shù)結(jié)束時(shí)會(huì)自動(dòng)關(guān)閉文件句柄。那么在 Python 里面可不可以實(shí)現(xiàn)類似的功能呢?本次來聊一聊 atexit 模塊,它能幫我們實(shí)現(xiàn)類似的效果。
import atexit def exit_func(words): print(words) # 將函數(shù)注冊(cè)進(jìn)去 atexit.register(exit_func, "高老師總能分享出好東西") print("Hello") print("World") """ Hello World 高老師總能分享出好東西 """
通過 atexit.register 將函數(shù)注冊(cè)進(jìn)去之后,會(huì)在程序結(jié)束之前執(zhí)行,當(dāng)然也可以同時(shí)注冊(cè)多個(gè)。
import atexit def exit_func(words): print(words) # 將函數(shù)注冊(cè)進(jìn)去 atexit.register(exit_func, "高老師總能分享出好東西") atexit.register(exit_func, "S 老師今年 18,單身帶倆娃") atexit.register(exit_func, "只因^(* ̄(oo) ̄)^只因大(出海版)") print("Hello") print("World") """ Hello World 只因^(* ̄(oo) ̄)^只因大(出海版) S 老師今年 18,單身帶倆娃 高老師總能分享出好東西 """
如果同時(shí)注冊(cè)了多個(gè)函數(shù),那么會(huì)按照先入后出的順序執(zhí)行。非常簡(jiǎn)單,其實(shí) atexit 模塊就是將我們注冊(cè)的函數(shù)保存在了一個(gè)數(shù)組中,程序結(jié)束的時(shí)候,從后往前依次執(zhí)行。
既然可以注冊(cè)函數(shù),那么也可以取消注冊(cè)。
import atexit def exit_func1(words): print(words) def exit_func2(words): print(words) atexit.register(exit_func1, "高老師總能分享出好東西") atexit.register(exit_func1, "S 老師今年 18,單身帶倆娃") atexit.register(exit_func2, "只因^(* ̄(oo) ̄)^只因大(出海版)") # 取消注冊(cè),所有注冊(cè)的 exit_func1 函數(shù)都會(huì)被刪除 atexit.unregister(exit_func1) """ 只因^(* ̄(oo) ̄)^只因大(出海版) """
而它的邏輯也很簡(jiǎn)單,就是遍歷數(shù)組,如果和指定的函數(shù)相等,那么就刪掉。我們看一下源代碼。
如果你想將注冊(cè)的函數(shù)全部取消掉,那么也可以調(diào)用 _clear() 函數(shù)。
import atexit def exit_func1(words): print(words) def exit_func2(words): print(words) atexit.register(exit_func1, "高老師總能分享出好東西") atexit.register(exit_func1, "S 老師今年 18,單身帶倆娃") atexit.register(exit_func2, "只因^(* ̄(oo) ̄)^只因大(出海版)") atexit._clear()
此時(shí)程序不會(huì)有任何輸出,因?yàn)樽?cè)的函數(shù)全部被清空了,同樣可以看一下它的源代碼。
最后就是函數(shù)的調(diào)用時(shí)機(jī),我們注冊(cè)的函數(shù)在程序結(jié)束時(shí)才會(huì)調(diào)用,可不可以讓它們?cè)谌我鈺r(shí)刻調(diào)用呢?
import atexit def exit_func1(words): print(words) def exit_func2(words): print(words) atexit.register(exit_func1, "AAA") atexit.register(exit_func1, "BBB") # 調(diào)用注冊(cè)的函數(shù),調(diào)用之后函數(shù)會(huì)被刪除 atexit._run_exitfuncs() print("++++++++++++++++") atexit.register(exit_func2, "CCC") atexit._run_exitfuncs() print("----------------") """ BBB AAA ++++++++++++++++ CCC ---------------- """
輸出結(jié)果表明,一旦調(diào)用了 _run_exitfuncs,所有注冊(cè)的函數(shù)會(huì)立即被調(diào)用。我們看一下源代碼。
以上就是 atexit 模塊的用法,那我們?nèi)绾位谒鼘?shí)現(xiàn) Golang 的 defer 呢?
from typing import Callable import atexit def defer(func: Callable, *args, **kwargs): atexit.register(func, *args, **kwargs) def get_file_content(file_path): fp = open(file_path, encoding="utf-8") defer(fp.close) # 注冊(cè)函數(shù) content = fp.read() # do something ... atexit._run_exitfuncs() # 觸發(fā)注冊(cè)函數(shù)執(zhí)行 get_file_content("config.py")
不過這個(gè)例子明顯有點(diǎn)刻意了,因?yàn)楸仨氁诤瘮?shù)的結(jié)尾調(diào)用 atexit._run_exitfuncs,而之所以要實(shí)現(xiàn) Go 的 defer,就是為了避免遺忘某些邏輯。
如果每次都要在函數(shù)結(jié)尾調(diào)用 atexit._run_exitfuncs,那還不如不用,于是我們可以考慮使用裝飾器。
from typing import Callable from functools import wraps import atexit def defer(func: Callable, *args, **kwargs): atexit.register(func, *args, **kwargs) # 給函數(shù)賦予 defer 功能 def enable_defer(func): @wraps(func) def inner(*args, **kwargs): ret = func(*args, **kwargs) atexit._run_exitfuncs() return ret return inner @enable_defer # 通過裝飾器,讓函數(shù)支持 defer 功能 def get_file_content(file_path): fp = open(file_path, encoding="utf-8") # 注冊(cè)函數(shù) defer(fp.close) defer(print, "get_file_content 函數(shù)實(shí)現(xiàn)了 defer 功能") content = fp.read() print("函數(shù)執(zhí)行結(jié)束") get_file_content("config.py") print("程序結(jié)束") """ 函數(shù)執(zhí)行結(jié)束 get_file_content 函數(shù)實(shí)現(xiàn)了 defer 功能 程序結(jié)束 """
輸出結(jié)果表明,在函數(shù)結(jié)束后,通過 defer 注冊(cè)的函數(shù)執(zhí)行了。
以上就是Python使用atexit模塊實(shí)現(xiàn)Golang的defer功能的詳細(xì)內(nèi)容,更多關(guān)于Python atexit實(shí)現(xiàn)defer功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用pytorch提取卷積神經(jīng)網(wǎng)絡(luò)的特征圖可視化
這篇文章主要給大家介紹了關(guān)于使用pytorch提取卷積神經(jīng)網(wǎng)絡(luò)的特征圖可視化的相關(guān)資料,文中給出了詳細(xì)的思路以及示例代碼,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-03-03Python+selenium 獲取瀏覽器窗口坐標(biāo)、句柄的方法
今天小編就為大家分享一篇Python+selenium 獲取瀏覽器窗口坐標(biāo)、句柄的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-10-10對(duì)pandas將dataframe中某列按照條件賦值的實(shí)例講解
今天小編就為大家分享一篇對(duì)pandas將dataframe中某列按照條件賦值的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-11-11python+openCV對(duì)視頻進(jìn)行截取的實(shí)現(xiàn)
這篇文章主要介紹了python+openCV對(duì)視頻進(jìn)行截取的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Python實(shí)現(xiàn)將Excel轉(zhuǎn)換成xml的方法示例
這篇文章主要介紹了Python實(shí)現(xiàn)將Excel轉(zhuǎn)換成xml的方法,涉及Python針對(duì)Excel文件的讀取、遍歷、節(jié)點(diǎn)設(shè)置與xml生成等相關(guān)操作技巧,需要的朋友可以參考下2018-08-08Python單元測(cè)試unittest模塊使用終極指南
本文將詳細(xì)介紹unittest模塊的各個(gè)方面,包括測(cè)試用例、斷言、測(cè)試套件、setUp和tearDown方法、跳過和期望異常、測(cè)試覆蓋率、持續(xù)集成等內(nèi)容,我們將提供豐富的示例代碼,以便讀者更好地理解如何使用unittest進(jìn)行單元測(cè)試2023-12-12Python實(shí)現(xiàn)程序的單一實(shí)例用法分析
這篇文章主要介紹了Python實(shí)現(xiàn)程序的單一實(shí)例用法,較為詳細(xì)的分析了Python窗口的相關(guān)操作技巧,需要的朋友可以參考下2015-06-06如何配置關(guān)聯(lián)Python 解釋器 Anaconda的教程(圖解)
這篇文章主要介紹了如何配置關(guān)聯(lián)Python 解釋器 Anaconda的教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)火鍋工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Python序列排序的具體場(chǎng)景實(shí)現(xiàn)
本文主要介紹了Python序列排序的具體場(chǎng)景實(shí)現(xiàn),主要介紹了內(nèi)置的sort()方法或者全局的sorted()方法著兩種方法,具有一定的參考價(jià)值,感興趣的可以了解一下2025-01-01