【问题标题】:Destructor (__del__) called before initialization (__init__) complete在初始化 (__init__) 完成之前调用的析构函数 (__del__)
【发布时间】:2020-04-12 14:33:06
【问题描述】:
class MyClass:
    def __init__(self):
        print("HEYYYYYYYYYY") # prints
        file = open("really_cool_file.txt")
        print("HOOOOOOOOOOOO") # does **NOT** print
        self._f = file
        print("WADUP!!!!!!!!!!") # does **NOT** print
        print(hasattr(self, "_f"))

    def __del__(self):
        print("closing any open files ")
        self._f.close()


my_instance = MyClass()
print("33333333333") # NEVER PRINTS

控制台输出如下:

HEYYYYYYYYYY
closing any open files 

我们收到以下错误消息:

C:\Users\Sam\AppData\Local\Programs\Python\Python38-32\python.exe 
H:/PYTHON_RECORD_VIDEO/dffhsrthrth.py
Traceback (most recent call last):
  File "H:/PYTHON_RECORD_VIDEO/dffhsrthrth.py", line 15, in <module>

    my_instance = MyClass()

  File "H:/PYTHON_RECORD_VIDEO/dffhsrthrth.py", line 4, in __init__
    file = open("really_cool_file.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'really_cool_file.txt'
Exception ignored in: <function MyClass.__del__ at 0x0383D1D8>
Traceback (most recent call last):
  File "H:/PYTHON_RECORD_VIDEO/dffhsrthrth.py", line 12, in __del__
    self._f.close()
AttributeError: 'MyClass' object has no attribute '_f'

Process finished with exit code 1

self._f = file 发生在__init__ 内部之前调用析构函数 我不明白如何在__init__ 完成执行之前调用析构函数。

【问题讨论】:

  • 小心使用__del__;如果您的对象因解释器退出而被删除,则不保证会调用它,就像这里的情况一样。

标签: python python-3.x destructor


【解决方案1】:

问题是您的open 呼叫失败;该异常导致__init__ 的其余部分被跳过(它直接冒泡而不执行初始化程序的其余部分),但__init__ 只是初始化程序,而不是构造函数,因此当对象时仍必须调用__del__被清理。由于您未能分配给self._f,因此终结器无法找到它。

__del__ 中引发的异常会被记录并忽略(因为它们不会以可预测的方式发生,因此没有安全的方法来处理它们),所以这不会破坏您的程序,只要打开文件被捕获和处理。

如果您想在这种情况下保持弹性(以避免出现第二条错误消息),只需让__del__ 更具弹性:

def __del__(self):
    print("closing any open files ")
    try:
        self._f.close()
    except AttributeError:
        pass  # Exception in constructor won't initialize _f; ignore it

【讨论】:

  • file = open("really_cool_file.txt") 引发异常,并且异常未处理。我认为如果没有捕获到异常,程序将立即终止。无需遍历每个变量,为每个变量重新分配内存。如果程序终止,则分配给该程序的所有内存都将变为空闲状态。绝对奇怪的是,如果引发了异常,并且没有捕获到异常,看起来 python 会到处删除程序中的每一条数据。 __del__ 被调用,这会引发 NEW 异常。
  • 如果有未处理的异常,程序应该STOP程序应该终止 -- 立即。如果你捕捉到异常,那么是的,事情会继续发生,但如果你没有捕捉到异常,那么程序应该停止。我不明白为什么 python 会在异常未处理后进行大量清理(包括为程序中的每个项目调用__del__)。
  • 假设程序崩溃时工作区中有3个变量。一旦程序停止运行,操作系统就会释​​放为该程序保留的所有内存,包括 3 个变量。曾经存在的工作空间,不再存在。在操作系统将其全部删除之前,python 绝对不需要删除工作区中的所有剩余/剩余数据。
  • 我不敢相信。 1) 发生错误。 2)python决定“关闭”当前“打开”的所有内容(我在这里松散地使用“打开”和“关闭”这两个词)3)python关闭时发生错误。这是没有意义的。想象一个计算机程序,一个人的桌子上到处都是文件。当一个程序“终止”时,操作系统会拿走桌子上的每一张纸,然后把它们扫进垃圾桶。 python没有必要事先扔掉它的纸质笔记。当一个程序死亡时,它的所有内存都会随之消失。
  • @ToothpickAnemone:你错过了这里的目的。释放内存(如您所见)毫无意义;操作系统会自动回收它。但并非所有程序状态都是瞬态的;正确关闭文件(并刷新仍在用户模式缓冲区中的数据),删除打开的NamedTemporaryFiles,执行任意的finally 块,其中一些外部状态被操纵并且正确性要求它执行等等是人们喜欢 发生;这不是必需的,但它很有帮助。我会注意到__del__ 中引发的异常会被记录,但会被忽略,因为没有有用的方法来响应它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多