【问题标题】:why i don't see destructor being called in python为什么我没有看到在 python 中调用析构函数
【发布时间】:2017-03-22 19:48:18
【问题描述】:

我正在开发一个用 python 编写的 API。我使用this 文章作为对python 析构函数的帮助。

# api.py
class ApiCfg(object):
    def __init__(self, ...):
        # open a connection to a device
        some_device_open()

    def __del__(self):
        print 'Close a connection to some_device'
        # close a connection to a device
        some_device_close()

# Some code
...
api_cfg = ApiCfg()

# myfile.py
from api import *

# Do some stuff
api.run()

一切完成后,我希望在屏幕上看到的是以下语句:Close connection to some device。但是由于某种原因我没有。有人可以解释为什么会这样吗?

【问题讨论】:

  • 您是否创建了A 类的实例?如果是,请准确说明您如何称呼它。您首先需要创建它的实例并存储在某个变量中。然后它会在退出时自动销毁并执行del
  • @RustemK 对不起。我犯了一个错误。 AApiCfg。现在修复它。
  • 是的,Python 实际上并不能保证调用 __del____del__ 不可靠。它在替代 Python 实现上更不可靠,并且标准实现不保证引用计数机制将保持不变。 Python 不是 C++;尝试像依赖 C++ 析构函数一样依赖 __del__ 是个坏主意。
  • @user2357112 那么关闭设备连接的建议是什么?
  • with 声明,主要是。

标签: python python-2.7 destructor


【解决方案1】:

即使所有操作都已完成,该对象仍会被引用。如果您想看到这一行出现,请在对象创建后终止程序。 Python 必须破坏每个对象,所以__del__ 方法将被运行。

但是,正如 cmets 中所指出的,Python 不保证会调用此方法。由于 Python 与垃圾收集器一起工作,因此不应该(或者更确切地说,不应该)手动破坏对象。如果您想确保调用您的 __del__ 方法,请调用 del 语句。

【讨论】:

  • 那么关闭与设备的连接的建议是什么?
  • @flashburn 手动关闭它。无论设备是什么,都应该有某种close 方法。如果异常有可能阻止关闭,请将其放在finally 块中。或者,如果它支持用作上下文管理器,请使用 with 语句。
  • @flashburn 是的,我建议您设计您的课程,使其支持上下文管理。这使用起来非常方便。
  • @Rightleg 那么我该如何设计它,当它被删除时设备连接关闭,我无法真正想象它。
  • @flasburn 上下文管理以这种方式工作: 1 - 使用with 语句(基础__enter__ 方法)创建您的对象; 2 - 创建一个新的范围(即缩进); 3 - 做你的事; 4 - 关闭调用__exit__ 方法的范围(即取消缩进)。基本上,__enter__ 创建并返回一个对象,__exit__ 执行必要的操作以干净的方式删除它。无论如何,当您离开上下文范围时,不再引用该对象,因此您不必手动删除它(因为Python)。但通常,__exit__ 应该关闭文件等。
【解决方案2】:

首先del 不保证它会被调用。这是某些垃圾收集器的“问题”,即:循环引用。

在您的特定情况下,我看到在初始化阶段ApiConfig.__init__ 您打开了与某些设备的连接。这意味着您可能增加了对象上的引用计数器(反之亦然)。通常当用户处理设备(文件、套接字、管道)时,他应该自己管理打开/关闭它,因为在其对象的引用计数器等于 0 之前不会调用 del。即为什么我们通常使用with 子句来包装正确管理设备生命周期的块的执行。例如:

with open("filename") as f:
     for line in f:
        pass

您可以使用contextlib.contextmanager 装饰器定义您自己的 with 子句,或者如果您需要更复杂的逻辑,则使用 enterexit 方法创建一个类。您可以在文档中查看更多信息并查看此article

您还可以通过创建并调用负责正确设备处理(包括正确关闭设备及其 gc)的 open()close() 方法以更直接的方式进行操作。

【讨论】:

  • @flashburn 你怎么看?满意的答案?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
  • 2018-11-19
  • 2021-08-04
  • 1970-01-01
  • 2010-12-21
相关资源
最近更新 更多