Python使用atexit模塊實現(xiàn)Golang的defer功能
在 Go 里面可以通過 defer 語句讓函數(shù)在結(jié)束時執(zhí)行預(yù)定義好的一些操作,舉個例子。
package main
import "fmt"
func main() {
defer fmt.Println("高老師總能分享出好東西")
fmt.Println("執(zhí)行結(jié)束")
/*
執(zhí)行結(jié)束
高老師總能分享出好東西
*/
}這個功能非常方便,比如打開文件之后可以執(zhí)行 defer fp.Close(),這樣函數(shù)結(jié)束時會自動關(guān)閉文件句柄。那么在 Python 里面可不可以實現(xiàn)類似的功能呢?本次來聊一聊 atexit 模塊,它能幫我們實現(xiàn)類似的效果。
import atexit
def exit_func(words):
print(words)
# 將函數(shù)注冊進(jìn)去
atexit.register(exit_func, "高老師總能分享出好東西")
print("Hello")
print("World")
"""
Hello
World
高老師總能分享出好東西
"""通過 atexit.register 將函數(shù)注冊進(jìn)去之后,會在程序結(jié)束之前執(zhí)行,當(dāng)然也可以同時注冊多個。
import atexit
def exit_func(words):
print(words)
# 將函數(shù)注冊進(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ù),那么會按照先入后出的順序執(zhí)行。非常簡單,其實 atexit 模塊就是將我們注冊的函數(shù)保存在了一個數(shù)組中,程序結(jié)束的時候,從后往前依次執(zhí)行。

既然可以注冊函數(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) ̄)^只因大(出海版)")
# 取消注冊,所有注冊的 exit_func1 函數(shù)都會被刪除
atexit.unregister(exit_func1)
"""
只因^(* ̄(oo) ̄)^只因大(出海版)
"""而它的邏輯也很簡單,就是遍歷數(shù)組,如果和指定的函數(shù)相等,那么就刪掉。我們看一下源代碼。

如果你想將注冊的函數(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ù)全部被清空了,同樣可以看一下它的源代碼。

最后就是函數(shù)的調(diào)用時機(jī),我們注冊的函數(shù)在程序結(jié)束時才會調(diào)用,可不可以讓它們在任意時刻調(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)用注冊的函數(shù),調(diào)用之后函數(shù)會被刪除
atexit._run_exitfuncs()
print("++++++++++++++++")
atexit.register(exit_func2, "CCC")
atexit._run_exitfuncs()
print("----------------")
"""
BBB
AAA
++++++++++++++++
CCC
----------------
"""輸出結(jié)果表明,一旦調(diào)用了 _run_exitfuncs,所有注冊的函數(shù)會立即被調(diào)用。我們看一下源代碼。

以上就是 atexit 模塊的用法,那我們?nèi)绾位谒鼘崿F(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) # 注冊函數(shù)
content = fp.read()
# do something
...
atexit._run_exitfuncs() # 觸發(fā)注冊函數(shù)執(zhí)行
get_file_content("config.py")不過這個例子明顯有點刻意了,因為必須要在函數(shù)的結(jié)尾調(diào)用 atexit._run_exitfuncs,而之所以要實現(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")
# 注冊函數(shù)
defer(fp.close)
defer(print, "get_file_content 函數(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ù)實現(xiàn)了 defer 功能
程序結(jié)束
"""輸出結(jié)果表明,在函數(shù)結(jié)束后,通過 defer 注冊的函數(shù)執(zhí)行了。
以上就是Python使用atexit模塊實現(xiàn)Golang的defer功能的詳細(xì)內(nèi)容,更多關(guān)于Python atexit實現(xiàn)defer功能的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python使用re模塊實現(xiàn)okenizer(表達(dá)式分詞器)
這篇文章主要介紹了Python使用re模塊實現(xiàn)okenizer,我們這里講解用正則表達(dá)式構(gòu)建簡單的表達(dá)式分詞器(tokenizer),它能夠?qū)⒈磉_(dá)式字符串從左到右解析為標(biāo)記(tokens)流,需要的朋友可以參考下2022-04-04
零基礎(chǔ)寫python爬蟲之抓取百度貼吧并存儲到本地txt文件改進(jìn)版
前面已經(jīng)發(fā)了一篇關(guān)于百度貼吧抓取的代碼,今天我們來看下代碼的改進(jìn)版,參考了上篇抓取糗事百科的思路,給需要的小伙伴們參考下吧2014-11-11

