在 Go 里面可以通過 defer 語句讓函數在結束時執行預定義好的一些操作,舉個例子。
package mainimport "fmt"func main() { defer fmt.Println("高老師總能分享出好東西") fmt.Println("執行結束") /* 執行結束 高老師總能分享出好東西 */}
這個功能非常方便,比如打開文件之后可以執行 defer fp.Close(),這樣函數結束時會自動關閉文件句柄。那么在 Python 里面可不可以實現類似的功能呢?本次來聊一聊 atexit 模塊,它能幫我們實現類似的效果。
import atexitdef exit_func(words): print(words)# 將函數注冊進去atexit.register(exit_func, "高老師總能分享出好東西")print("Hello")print("World")"""HelloWorld高老師總能分享出好東西"""
通過 atexit.register 將函數注冊進去之后,會在程序結束之前執行,當然也可以同時注冊多個。
import atexitdef exit_func(words): print(words)# 將函數注冊進去atexit.register(exit_func, "高老師總能分享出好東西")atexit.register(exit_func, "S 老師今年 18,單身帶倆娃")atexit.register(exit_func, "只因^(* ̄(oo) ̄)^只因大(出海版)")print("Hello")print("World")"""HelloWorld只因^(* ̄(oo) ̄)^只因大(出海版)S 老師今年 18,單身帶倆娃高老師總能分享出好東西"""
如果同時注冊了多個函數,那么會按照先入后出的順序執行。非常簡單,其實 atexit 模塊就是將我們注冊的函數保存在了一個數組中,程序結束的時候,從后往前依次執行。
圖片
既然可以注冊函數,那么也可以取消注冊。
import atexitdef 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) ̄)^只因大(出海版)")# 取消注冊,所有注冊的 exit_func1 函數都會被刪除atexit.unregister(exit_func1)"""只因^(* ̄(oo) ̄)^只因大(出海版)"""
而它的邏輯也很簡單,就是遍歷數組,如果和指定的函數相等,那么就刪掉。我們看一下源代碼。
圖片
如果你想將注冊的函數全部取消掉,那么也可以調用 _clear() 函數。
import atexitdef 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()
此時程序不會有任何輸出,因為注冊的函數全部被清空了,同樣可以看一下它的源代碼。
圖片
最后就是函數的調用時機,我們注冊的函數在程序結束時才會調用,可不可以讓它們在任意時刻調用呢?
import atexitdef exit_func1(words): print(words)def exit_func2(words): print(words)atexit.register(exit_func1, "AAA")atexit.register(exit_func1, "BBB")# 調用注冊的函數,調用之后函數會被刪除atexit._run_exitfuncs()print("++++++++++++++++")atexit.register(exit_func2, "CCC")atexit._run_exitfuncs()print("----------------")"""BBBAAA++++++++++++++++CCC----------------"""
輸出結果表明,一旦調用了 _run_exitfuncs,所有注冊的函數會立即被調用。我們看一下源代碼。
圖片
以上就是 atexit 模塊的用法,那我們如何基于它實現 Golang 的 defer 呢?
from typing import Callableimport atexitdef 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) # 注冊函數 content = fp.read() # do something ... atexit._run_exitfuncs() # 觸發注冊函數執行get_file_content("config.py")
不過這個例子明顯有點刻意了,因為必須要在函數的結尾調用 atexit._run_exitfuncs,而之所以要實現 Go 的 defer,就是為了避免遺忘某些邏輯。
如果每次都要在函數結尾調用 atexit._run_exitfuncs,那還不如不用,于是我們可以考慮使用裝飾器。
from typing import Callablefrom functools import wrapsimport atexitdef defer(func: Callable, *args, **kwargs): atexit.register(func, *args, **kwargs)# 給函數賦予 defer 功能def enable_defer(func): @wraps(func) def inner(*args, **kwargs): ret = func(*args, **kwargs) atexit._run_exitfuncs() return ret return inner@enable_defer # 通過裝飾器,讓函數支持 defer 功能def get_file_content(file_path): fp = open(file_path, encoding="utf-8") # 注冊函數 defer(fp.close) defer(print, "get_file_content 函數實現了 defer 功能") content = fp.read() print("函數執行結束")get_file_content("config.py")print("程序結束")"""函數執行結束get_file_content 函數實現了 defer 功能程序結束"""
輸出結果表明,在函數結束后,通過 defer 注冊的函數執行了。
以上就是用 Python 實現 Go 的 defer,不過在工作中還是不建議這么做,沒啥必要,這里只是想分享一下 atexit 模塊。
本文鏈接:http://www.www897cc.com/showinfo-26-82736-0.html通過 Atexit 模塊讓 Python 實現 Golang 的 defer 功能,你學會了嗎?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com