【问题标题】:del self vs self.__del__() - and what is the proper way to cleanup in python?del self vs self.__del__() - 在python中清理的正确方法是什么?
【发布时间】:2017-01-20 14:15:40
【问题描述】:

我有一个包含类的 python 脚本。

这个类有一个__del__ 用于通常清理的方法。如果我在脚本正常执行期间删除了类,我希望进行一些清理。

我还有一个信号处理程序,它会进行一些不寻常的清理。如果脚本在收到信号时正在执行其他操作,则需要进行一些额外的清理,然后进行常规清理。

我注意到del selfself.__del__() 之间存在区别。

self.__del__()调用del方法两次。

你能解释一下为什么会这样吗?

这是一个用于说明问题的模型脚本:

import sys
import signal
from optparse import OptionParser


class TestClass(object):
    def __init__(self,
                 del_self):
        self.del_self = del_self

        print "__init__ with del_self = %s" % self.del_self

    def __del__(self):
        print "Now performing usual cleanup."

    def signal_handler(self, arg_1, arg_2):
        print "Received signal. Now performing unusual cleanup."

        # Unusual cleanup

        print "Did unusual cleanup"

        if self.del_self:
            print("Doing del self")
            del self
        else:
            print("Doing self.__del__()")
            self.__del__()

        sys.exit(0)


if __name__ == '__main__':
    arguments = sys.argv[1:]
    parse = OptionParser("Test.")
    parse.add_option(
        "-d",
        "--delself",
        help="Set del self.",
        type="int",
        default=1
    )

    (options, _) = parse.parse_args()

    print "Options: %s" % options

    tc = TestClass(del_self=options.delself)

    signal.signal(signal.SIGQUIT, tc.signal_handler)

    while True:
        pass

如果我运行脚本:

python deltest.py --delself 1

然后发出killall -3 python 我明白了:

Received signal. Now performing unusual cleanup.
Did unusual cleanup
Doing del self
Now performing usual cleanup.

如果我再次执行 python deltest.py --delself 0 后跟 kill 信号,我会得到:

Received signal. Now performing unusual cleanup.
Did unusual cleanup
Doing self.__del__()
Now performing usual cleanup.
Now performing usual cleanup.

为什么在这种情况下__del__ 方法会执行两次?

谢谢!

【问题讨论】:

    标签: python python-2.7 python-3.x self code-cleanup


    【解决方案1】:

    del self 几乎什么都不做——它只删除名为self局部变量。但由于这不是对实例的最后一个引用(至少,这个方法仍然有一个引用),所以该对象将继续存在。

    手动调用__del__ 除了运行那个方法之外什么也没有;它不会删除任何内容。

    所做 的工作是删除对对象的最后一个引用:在这种情况下,据我所知,main 方法中的del tc 将删除最后一个引用。然后该对象将被垃圾回收,然后 Python 调用__del__

    这就是__del__ 发生两次的原因:一次是您将其作为普通函数手动调用,另一次是在程序结束时对象被垃圾回收。

    【讨论】:

    • @random_person_123:是的,这个有详细解释here
    • 所以,为了确保我理解正确,因为 del 在垃圾收集开始时被调用,我不必在我的信号处理程序中调用它,因为当实例被垃圾收集时它会自动调用。这是正确的吗?
    • @random_person_123:是的,你永远不会自己调用它,它会在对象被垃圾回收时自动调用。请注意,官方 Python 不保证 何时 你的对象会被垃圾回收,尽管 CPython 通常会在最后一个引用消失时这样做。
    • @RemcoGerlich,好的,这是有道理的。在 SIGQUIT 信号的情况下,引用是否设置为 0?我实际上要问的是,我怎样才能保证在信号处理程序运行时执行我通常的清理,而不会重复代码。
    • 保证在解释器退出时运行。因此,如果您的__del__ 的编写方式可以安全地多次调用它,那么在调用 sys.exit 之前自己调用它可能是个好主意。
    猜你喜欢
    • 2019-12-06
    • 2020-06-16
    • 2017-08-28
    • 1970-01-01
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    相关资源
    最近更新 更多