【问题标题】:Python object deletion detectionPython对象删除检测
【发布时间】:2012-09-14 22:21:24
【问题描述】:

我正在为 C++ 程序的 swig 接口构建一个 Python 包装器。

我很想知道 Python 对象是否有办法“知道”它是如何被删除的。这个想法很简单,如果垃圾收集器删除了对象,则包装器不会对底层 C++ 对象做任何事情,但如果用户故意删除了对象(``del 对象),那么包装器会检测到该对象并取消引用底层对象,以便它也被删除。

我已经尝试过用谷歌搜索,但找不到任何东西。我发现的唯一一件事是(显然)__del__ 被垃圾收集器和 del 命令调用,似乎无法区分是哪个调用它。

希望有人证明我错了!

【问题讨论】:

  • 这里的问题是del 只删除了一个引用,它并不能保证对象被删除——所以实际上所有的删除都是由垃圾收集器完成的。
  • 你错了。正如 Lattyware 所提到的,del 只删除了一个引用,该对象可能从此过上幸福的生活,或者可能变得无法访问。在任何情况下,只有自动内存管理调用__del__,但不能保证。事实上,在很多情况下定义 __del__ 防止 清理(即它不被调用)。请参阅documentation
  • @delnan:有趣的是,PyPy 通过随机选择一个要删除的对象来破坏循环引用,__del__ 钩子与否。
  • @MartijnPieters 是的,这表明实现定义这些东西是多么疯狂。你真的不能依赖任何东西。例如,如果__del__ 恢复(例如存储在全局中)对象,CPython 将重复调用__del__,但 PyPy 只会调用一次。如果类没有定义__del__ 方法,PyPy 也不会尊重附加到单个对象的__del__。不要问我为什么我知道这些晦涩的东西o.O
  • 我非常同意;我仅以 PyPy 为例指出 GC 行为是依赖于实现的。

标签: c++ python oop wrapper swig


【解决方案1】:

CPython 使用引用计数来跟踪对象的生命周期。因此,所有删除都由垃圾收集器完成。

例如,下面的代码创建了两个引用; __del__ 钩子只被调用一次,在对象的第二个引用被删除后:

>>> class Foo(object):
...     def __del__(self):
...         print "Bye bye!"
... 
>>> spam = Foo()
>>> bar = spam
>>> del spam
>>> del bar
Bye bye!

因此,无法通过__del__ 挂钩检测单个del 语句;它总是只被垃圾收集器调用。

请注意,某些 python 实现(尤其是 cpython)使用 __del__ 钩子清除对象,这些对象是循环依赖项的一部分。这并不适用于所有实现,但值得记住。

无论如何,使用引用计数来实现对象删除和垃圾回收本身就是一个实现细节,非 CPython 实现可以(并且确实)完全不同地处理对象删除。

【讨论】:

  • 讨论多个实现的加分项(并将 CPython 视为例外)。但是第一句话不适合,因为它只适用于 CPython,而不是所有的 Python 实现。到目前为止,Refcounting 是真正的实现细节,实际上所有不是直接从 CPython 派生的实现都不会这样做。
  • @delnan:在那里,添加了C 以澄清。由于 OP 正在讨论为 python 库创建 C++ swig 包装器,因此我们当然在这里处理 CPython。
猜你喜欢
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多