如何创建正确垃圾收集的自定义生成器类

2023-12-08

我正在尝试用 Python 编写一个类,其行为类似于生成器对象,特别是当它被垃圾收集时.close()被调用。这很重要,因为这意味着当生成器被中断时,我可以确保它会自行清理,例如关闭文件或释放锁。

这是一些解释性代码: 如果你中断一个生成器,那么当它被垃圾收集时,Python 会调用.close()在生成器对象上,它会抛出一个GeneratorExit生成器中出现错误,可以捕获该错误以进行清理,如下所示:

from threading import Lock

lock = Lock()

def CustomGenerator(n, lock):
    lock.acquire()
    print("Generator Started: I grabbed a lock")
    try:
        for i in range(n):
            yield i
    except GeneratorExit:
        lock.release()
        print("Generator exited early: I let go of the lock")
        raise
    print("Generator finished successfully: I let go of the lock")

for i in CustomGenerator(100, lock):
    print("Received ", i)
    time.sleep(0.02)
    if i==3:
        break

if not lock.acquire(blocking=False):
    print("Oops: Finished, but lock wasn't released")
else:
    print("Finished: Lock was free")
    lock.release()
Generator Started: I grabbed a lock
Received  0
Received  1
Received  2
Received  3
Generator exited early: I let go of the lock
Finished: Lock was free

但是,如果您尝试通过继承来实现自己的生成器对象collections.abc.Generator,Python似乎没有注意到它应该在对象被收集时调用close:

from collections.abc import Generator
class CustomGeneratorClass(Generator):
    def __init__(self, n, lock):
        super().__init__()
        self.lock = lock
        self.lock.acquire()
        print("Generator Class Initialised: I grabbed a lock")
        self.n = n
        self.c = 0

    def send(self, arg):
        value = self.c
        if value >= self.n:
            raise StopIteration
        self.c += 1
        return value

    def throw(self, type, value=None, traceback=None):
        print("Exception Thrown in Generator: I let go of the lock")
        self.lock.release()
        raise StopIteration

for i in CustomGeneratorClass(100, lock):
    print("Received ", i)
    time.sleep(0.02)
    if i==3:
        break

if not lock.acquire(blocking=False):
    print("Oops: Finished, but lock wasn't released")
else:
    print("Finished: Lock was free")
    lock.release()
Generator Class Initialised: I grabbed a lock
Received  0
Received  1
Received  2
Received  3
Oops: Finished, but lock wasn't released

我以为继承Generator足以让 python 相信我的 CustomGeneratorClass 是一个生成器并且应该具有.close()垃圾收集时调用它。

我认为这与“生成器对象”是某种特殊的事实有关Generator:

from types import GeneratorType

c_gen = CustomGenerator(100)
c_gen_class = CustomGeneratorClass(100)

print("CustomGenerator is a Generator:", isinstance(c_gen, Generator))
print("CustomGenerator is a GeneratorType:",isinstance(c_gen, GeneratorType))

print("CustomGeneratorClass is a Generator:",isinstance(c_gen_class, Generator))
print("CustomGeneratorClass is a GeneratorType:",isinstance(c_gen_class, GeneratorType))
CustomGenerator is a Generator: True
CustomGenerator is a GeneratorType: True
CustomGeneratorClass is a Generator: True
CustomGeneratorClass is a GeneratorType: False

我可以创建一个用户定义的类对象吗GeneratorType?

关于 python 如何决定调用什么,有什么我不明白的地方吗.close() on?

我怎样才能确保.close()在我的自定义生成器上调用?


这个问题不是重复的如何编写生成器类。 对于实际创建一个生成器类,该问题的可接受答案确实推荐了我在这里尝试的结构,它是一个生成器类,但没有正确地进行垃圾收集,如上面的代码所示。


PEP342, 状态:

[generator].__del__()是一个包装器[generator].close()。当生成器对象被垃圾收集时,这将被调用......

中的生成器类集合.abc不实施__del__,它的超类或元类也没有。

添加这个实现__del__到问题中的类会导致锁被释放:

class CustomGeneratorClass(Generator):

    ...

    def __del__(self):
        self.close() 

Output:

Generator Class Initialised: I grabbed a lock
Recieved  0
Recieved  1
Recieved  2
Recieved  3
Exception Thrown in Generator: I let go of the lock
Finished: Lock was free

Caveat:

我对 Python 中对象终结的复杂性没有经验,因此应该仔细检查此建议,并进行破坏测试。特别是关于以下警告__del__ in the 语言参考应该被考虑。


更高级别的解决方案是在上下文管理器中运行生成器

with contextlib.closing(CustomGeneratorClass(100, lock)):
    # do stuff

但这很麻烦,并且依赖于代码的用户记得这样做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何创建正确垃圾收集的自定义生成器类 的相关文章

随机推荐

  • 在 Python 中查找偶数

    我有一个 Python 作业 如下所示 编写一个完整的 python 程序 要求用户输入两个整数 然后程序输出Both Even如果两个整数都是偶数 否则程序输出Not Both Even 我计划使用 if 和 else 语句 但由于我正在
  • 为什么必须在头文件中定义两次变量?

    为什么必须在头文件中定义两次变量 这些变量之间有什么区别 第一个定义在这里 interface MyController UIViewController NSInteger selectedIndex 第二个定义在这里 property
  • C++ 和 cUrl:如何获取 SSL 错误代码

    我正在通过 SSL 建立与安全服务器的连接 一切正常 我的 CA 证书很好用 retCode curl easy setopt handleCurl CURLOPT CAINFO sSSLCertificate retCode curl e
  • php 会话变量不起作用

    以下是我的登录页面的代码 其中登录脚本检查用户的真实性 然后使用标头函数重定向到收件箱页面
  • 使用批处理文件关闭文件夹窗口

    我的桌面上有一个名为test 我想创建一个批处理文件 以便在使用 Windows 资源管理器打开此文件夹时自动关闭窗口 我尝试了下一个命令 但执行时没有任何反应 TASKKILL F FI WINDOWTITLE eq test IM ex
  • Google脚本-超出最大执行时间,帮助优化

    谷歌脚本电子表格 新手 我尝试创建一个矩阵 如果数组是一个小型数据库 一切正常 当然 如果它超过 800 行 更多则取决于错误 您已超出允许的最大运行时间 无法有效创建矩阵 var s SpreadsheetApp getActiveShe
  • 如何在 python 函数的声明中找到其名称引用?

    这是完全出乎意料的 至少对我来说 foo会知道foo函数内部def for foo 这到底是怎么回事 gt gt gt def foo x print wow print globals get foo sorry return foo g
  • 旋转屏幕后找不到微调器

    我正在使用 片段 来获取具有两个 片段 的布局 因此我的类扩展了 片段 我正在左侧 片段 上加载 ListView 在右侧 片段 上加载另一个修改后的 ListView 在这里 我有一个 旋转器 我必须改变它的颜色 我有这个代码 priva
  • 两个并排的 div,一个带有谷歌地图,第二个带有固定宽度

    我想并排使用两个 DIV 第一个 DIV 具有响应宽度 内部带有谷歌地图 第二个 DIV 具有固定宽度 jsFiddle 示例 HTML div class wrapper div div div class right div div C
  • 如何修复 java.lang.arrayindexoutofboundsException: 0?

    我是新手java 谁能帮我解决这个错误arrayindexoutofboundsexception public class Minesweeper public static void main String args int M Int
  • 使用刷新令牌进行 C#sharp 身份验证的 Google.Apis 客户端

    我正在使用适用于 NET 的新测试版 Google API 客户端库来加载多个用户的任务列表 它被归类为 已安装的应用程序 根据谷歌开发控制台 具有多个授权用户帐户 验证一个用户的身份非常简单 使用 google apis 但我不知道如何使
  • 访问复合数组元素 plpgsql

    我有一个用户定义的复合数据类型的数组 我需要对 plpgsql 函数中的数组元素进行一些操作 但我没有获得访问各个元素的正确语法 任何帮助表示赞赏 下面粘贴的是代码的简化版本 CREATE TYPE playz AS a integer b
  • bash 中具有算术比较行为的 if 语句

    我正在学习 bash 我注意到一些奇怪的东西我 还 无法解释 在学校我了解到 if 语句将 0 评估为真 将 1 评估为假 因此它可以与其他命令的状态代码一起使用 现在我的问题是 为什么会发生这种情况 echo 5 gt 2 prints
  • 低落和昂扬

    我是新来的C and OOP 当我有如下代码时 class Employee some code class Manager Employee some code 问题1 如果我有其他代码可以执行此操作 Manager mgr new Ma
  • Java fxml 应用程序无法正常工作 - 找不到符号错误

    我从下载了一个java fxml应用程序https github com HassanAlthaf AlarmApplication当我尝试运行它时 从 MainView java 类中收到 找不到符号 错误 这是 Mainview jav
  • 带“+”的类名

    我正在 Xcode 中开发一个 iOS 项目 我看到一些类的名称带有 例如 TableViewController TableView h然后该类被命名为 interface RKTableViewController TableView
  • 将数据透视表写入 Excel 文件时遇到问题

    我正在使用 pandas openpyxl 处理 Excel 文件 然后创建一个数据透视表以添加到当前工作簿中的新工作表 当我执行代码时 会创建新工作表 但数据透视表不会添加到工作表中 这是我的代码 worksheet2 workbook
  • MSVC项目中使用的Mingw静态库

    是否可以在 Visual Studio MSVC 项目中使用使用 mingw 编译的静态库 这两个项目都是 C 我还没有找到明确的答案 请注意 我说的是静态库而不是 DLL 不 这是不可能的 因为ABI对于 c 来说不是标准的gcc的 AB
  • 使用python获取当月的最后一个星期四

    按照此answer我试图获取本月最后一个星期四的日期 但我的代码没有脱离循环 from datetime import datetime from dateutil relativedelta import relativedelta TH
  • 如何创建正确垃圾收集的自定义生成器类

    我正在尝试用 Python 编写一个类 其行为类似于生成器对象 特别是当它被垃圾收集时 close 被调用 这很重要 因为这意味着当生成器被中断时 我可以确保它会自行清理 例如关闭文件或释放锁 这是一些解释性代码 如果你中断一个生成器 那么