如何正确清理 Python 对象?

新手上路,请多包涵
class Package:
    def __init__(self):
        self.files = []

    # ...

    def __del__(self):
        for file in self.files:
            os.unlink(file)

__del__(self) 以上失败并出现 AttributeError 异常。我知道当调用 __del__() 时, Python 不保证 存在“全局变量”(这种情况下的成员数据?)。如果是这种情况并且这是异常的原因,我如何确保对象正确销毁?

原文由 wilhelmtell 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 429
2 个回答

我建议使用 Python 的 with 语句来管理需要清理的资源。使用显式 close() 语句的问题在于,您必须担心人们根本忘记调用它或忘记将其放在 finally 块中以防止资源泄漏发生异常。

要使用 with 语句,请使用以下方法创建一个类:

   def __enter__(self)
  def __exit__(self, exc_type, exc_value, traceback)

在上面的示例中,您将使用

class Package:
    def __init__(self):
        self.files = []

    def __enter__(self):
        return self

    # ...

    def __exit__(self, exc_type, exc_value, traceback):
        for file in self.files:
            os.unlink(file)

然后,当有人想使用您的课程时,他们会执行以下操作:

 with Package() as package_obj:
    # use package_obj

变量 package_obj 将是 Package 类型的实例(它是 __enter__ 方法返回的值)。它的 __exit__ 方法会自动被调用,无论是否发生异常。

您甚至可以将这种方法更进一步。在上面的例子中,人们仍然可以使用它的构造函数来实例化 Package 而无需使用 with 子句。你不希望这种情况发生。您可以通过创建一个 PackageResource 类来解决此问题,该类定义了 __enter____exit__ 方法。然后,Package 类将在 __enter__ 方法中严格定义并返回。这样,调用者在不使用 with 语句的情况下永远无法实例化 Package 类:

 class PackageResource:
    def __enter__(self):
        class Package:
            ...
        self.package_obj = Package()
        return self.package_obj

    def __exit__(self, exc_type, exc_value, traceback):
        self.package_obj.cleanup()

您可以按如下方式使用它:

 with PackageResource() as package_obj:
    # use package_obj

原文由 Clint Miller 发布,翻译遵循 CC BY-SA 3.0 许可协议

标准方法是使用 atexit.register

 # package.py
import atexit
import os

class Package:
    def __init__(self):
        self.files = []
        atexit.register(self.cleanup)

    def cleanup(self):
        print("Running cleanup...")
        for file in self.files:
            print("Unlinking file: {}".format(file))
            # os.unlink(file)

但是你应该记住,这将保留所有创建的 Package 实例,直到 Python 终止。

Demo 使用上面的代码保存为 package.py

 $ python
>>> from package import *
>>> p = Package()
>>> q = Package()
>>> q.files = ['a', 'b', 'c']
>>> quit()
Running cleanup...
Unlinking file: a
Unlinking file: b
Unlinking file: c
Running cleanup...

原文由 ostrokach 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏