Python使用atexit模块实现Golang的defer功能

 更新时间:2024年04月11日 14:25:22   作者:古明地觉的编程教室  
这篇文章主要为大家详细介绍了Python如何使用atexit模块实现Golang的defer功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

在 Go 里面可以通过 defer 语句让函数在结束时执行预定义好的一些操作,举个例子。

package main

import "fmt"

func main() {
    defer fmt.Println("高老师总能分享出好东西")
    fmt.Println("执行结束")
    /*
    执行结束
    高老师总能分享出好东西
    */
}

这个功能非常方便,比如打开文件之后可以执行 defer fp.Close(),这样函数结束时会自动关闭文件句柄。那么在 Python 里面可不可以实现类似的功能呢?本次来聊一聊 atexit 模块,它能帮我们实现类似的效果。

import atexit

def exit_func(words):
    print(words)

# 将函数注册进去
atexit.register(exit_func, "高老师总能分享出好东西")
print("Hello")
print("World")
"""
Hello
World
高老师总能分享出好东西
"""

通过 atexit.register 将函数注册进去之后,会在程序结束之前执行,当然也可以同时注册多个。

import atexit

def exit_func(words):
    print(words)

# 将函数注册进去
atexit.register(exit_func, "高老师总能分享出好东西")
atexit.register(exit_func, "S 老师今年 18,单身带俩娃")
atexit.register(exit_func, "只因^(* ̄(oo) ̄)^只因大(出海版)")
print("Hello")
print("World")
"""
Hello
World
只因^(* ̄(oo) ̄)^只因大(出海版)
S 老师今年 18,单身带俩娃
高老师总能分享出好东西
"""

如果同时注册了多个函数,那么会按照先入后出的顺序执行。非常简单,其实 atexit 模块就是将我们注册的函数保存在了一个数组中,程序结束的时候,从后往前依次执行。

既然可以注册函数,那么也可以取消注册。

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 函数都会被删除
atexit.unregister(exit_func1)
"""
只因^(* ̄(oo) ̄)^只因大(出海版)
"""

而它的逻辑也很简单,就是遍历数组,如果和指定的函数相等,那么就删掉。我们看一下源代码。

如果你想将注册的函数全部取消掉,那么也可以调用 _clear() 函数。

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

此时程序不会有任何输出,因为注册的函数全部被清空了,同样可以看一下它的源代码。

最后就是函数的调用时机,我们注册的函数在程序结束时才会调用,可不可以让它们在任意时刻调用呢?

import atexit

def 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("----------------")
"""
BBB
AAA
++++++++++++++++
CCC
----------------
"""

输出结果表明,一旦调用了 _run_exitfuncs,所有注册的函数会立即被调用。我们看一下源代码。

以上就是 atexit 模块的用法,那我们如何基于它实现 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)  # 注册函数
    content = fp.read()
    # do something
    ...
    atexit._run_exitfuncs()  # 触发注册函数执行

get_file_content("config.py")

不过这个例子明显有点刻意了,因为必须要在函数的结尾调用 atexit._run_exitfuncs,而之所以要实现 Go 的 defer,就是为了避免遗忘某些逻辑。

如果每次都要在函数结尾调用 atexit._run_exitfuncs,那还不如不用,于是我们可以考虑使用装饰器。

from typing import Callable
from functools import wraps
import atexit

def 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使用atexit模块实现Golang的defer功能的详细内容,更多关于Python atexit实现defer功能的资料请关注脚本之家其它相关文章!

相关文章

  • Python re模块介绍

    Python re模块介绍

    这篇文章主要介绍了Python re模块介绍,需要的朋友可以参考下
    2014-11-11
  • mac下如何将python2.7改为python3

    mac下如何将python2.7改为python3

    这篇文章主要介绍了mac下如何将python2.7改为python3,本文分步骤给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-07-07
  • Python使用re模块实现okenizer(表达式分词器)

    Python使用re模块实现okenizer(表达式分词器)

    这篇文章主要介绍了Python使用re模块实现okenizer,我们这里讲解用正则表达式构建简单的表达式分词器(tokenizer),它能够将表达式字符串从左到右解析为标记(tokens)流,需要的朋友可以参考下
    2022-04-04
  • python实操练习案例(一)

    python实操练习案例(一)

    这篇文章主要介绍了python实操练习案例,下面文章小编要给大家分享的是适合python初学者的小练习,需要的小伙伴可以参考一下
    2022-02-02
  • Python语言生成水仙花数代码示例

    Python语言生成水仙花数代码示例

    这篇文章主要介绍了Python语言生成水仙花数代码示例,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • python聊天程序实例代码分享

    python聊天程序实例代码分享

    这篇文章主要介绍了用python写的聊天程序,开两个线程,即是客户端,也是服务器,大家可以参考使用
    2013-11-11
  • pandas中位数填充空值的实现示例

    pandas中位数填充空值的实现示例

    中位数填充是一种简单而有效的方法,用于填充数据集中缺失的值,本文就来介绍一下pandas中位数填充空值的实现,具有一定的参考价值,感兴趣的可以了解一下
    2025-04-04
  • 零基础写python爬虫之抓取百度贴吧并存储到本地txt文件改进版

    零基础写python爬虫之抓取百度贴吧并存储到本地txt文件改进版

    前面已经发了一篇关于百度贴吧抓取的代码,今天我们来看下代码的改进版,参考了上篇抓取糗事百科的思路,给需要的小伙伴们参考下吧
    2014-11-11
  • Python中切片操作符的具体使用

    Python中切片操作符的具体使用

    Python切片操作用于提取序列(如列表、字符串)的子集,支持正负索引和步长,返回浅拷贝新对象,切片操作通常用于列表、元组、字符串等,下面就具体来了解一下
    2025-07-07
  • Python语言实现科学计算器

    Python语言实现科学计算器

    这篇文章主要为大家详细介绍了Python语言实现科学计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01

最新评论