【问题标题】:Calling destructor function in middle of the program在程序中间调用析构函数
【发布时间】:2020-05-08 21:52:30
【问题描述】:

我有一个关于在程序中间销毁对象和调用析构函数的问题。

例如:

class ABC: 

    # Initializing 
    def __init__(self): 
        print('Constructor Called') 

    # Destructor 
    def __del__(self): 
        print('Destructor called')

obj = ABC() 
del obj 
# I want destructor to be called here.
# and then print below statement
print("obj deleted") 

而是在程序结束时调用析构函数。

任何帮助开发者?

【问题讨论】:

  • 当我运行这段代码时,我得到Constructor Called Destructor called obj deleted
  • 你没有打电话给__del__;你使用了del,这可能间接导致__del__被调用。尽管该对象有资格被垃圾收集,但如果出于某种原因将其延迟到程序完成之前我不会感到惊讶,并且退出的解释器不必这样做 任何垃圾收集。 __del__ 根本不应该被调用。

标签: python python-3.x oop memory-management destructor


【解决方案1】:

__del__() (here) 的文档中有详细说明:

注意del x不直接调用x.__del__()——前者将x的引用计数减一,而后者仅在x的引用计数为零时调用。

如果您尝试“解构”一个 Python 对象(并注意我在引号中是如何说的),我建议您使用 __exit__()with 语句(文档 here)。

要使用with 语句,您可以使用以下方法定义一个类:

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

一个简单的例子如下:

class Bar:
    def __init__(self, *args):
        self.stack = list(args)

    def __enter__(self):
        # Example computation here.
        filtered = filter(lambda x: isinstance(x, str), self.stack)
        return list(filtered)

    def __exit__(self, exc_type, exc_value, traceback):
        del self.stack

# Once you leave the 'with' statement, this Bar() object will be deleted for good. 
with Bar("Hello", "World!", 1, 2) as stack:
    print(stack)

坦率地说,在 Python 中“解构”一个对象几乎是不需要的,在大多数情况下,您应该在编程时避免尝试完成 garbage collector 的工作。使用del 是一回事,但试图“解构”一个对象是另一回事。

【讨论】:

  • 非常感谢@Felipe 提供如此快速且内容丰富的答案。你的回答真的很有帮助
【解决方案2】:

__del__ 方法在对象的引用计数达到 0 时调用,或者在循环引用的情况下被垃圾回收器遍历时调用。例如:

class Foo:
    def __del__(self):
        print('Foo has been deleted!')

foo = Foo()
del foo

可以正确调用__del__ 方法并打印Foo has been deleted!,因为分配给foo 的对象仅被引用一次。现在让我们看看下面的例子:

class Foo:
    def __del__(self):
        print('Foo has been deleted!')

foo = Foo()
foo.self = foo
del foo

__del__ 方法不会被调用,因为foo.self 将自己作为人质。只有在被垃圾收集器遍历时才会被删除。例如:

from gc import collect

class Foo:
    def __del__(self):
        print('Foo has been deleted!')

foo = Foo()
foo.self = foo
del foo

collect()

__del__ 方法将被调用,因为我们告诉收集器遍历待处理的对象。不推荐,但您可以通过将阈值设置为 1 来告诉 Python 遍历所有队列。例如:

from gc import set_threshold

set_threshold(1, 1, 1)

class Foo:
    def __del__(self):
        print('Foo has been deleted!')

foo = Foo()
foo.self = foo
del foo

因此,每次实例化 1 个对象时,收集器都会运行。但同样,不建议这样做,因为它可能成本高昂并影响代码的性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 2018-05-08
    • 2013-06-24
    • 1970-01-01
    相关资源
    最近更新 更多