我的__del__()可能会引发ResourceWarning.KeyboardInterrupt会导致不必要的警告吗



以从python-3.9.0/Lib/asyncore.py-复制的示例为例

class file_wrapper:
# Here we override just enough to make a file
# look like a socket for the purposes of asyncore.
# The passed fd is automatically os.dup()'d
def __init__(self, fd):
self.fd = os.dup(fd)
def __del__(self):
if self.fd >= 0:
warnings.warn("unclosed file %r" % self, ResourceWarning,
source=self)
self.close()
# ...
def close(self):
if self.fd < 0:
return
fd = self.fd
self.fd = -1
os.close(fd)
# ...

ResourceWarning的目的是在您的程序出现错误时发出警告;"泄漏";资源。让我们试着写一个没有任何这样的错误的程序:

def test():
f = None
try:
f = file_wrapper(sys.stdin.fileno)
os.write(self.f.fd, b'!')
finally:
if f:
f.close()

在cpython中,假设控制台中断发生在CALL_UNCTION操作码之后和STORE_FAST操作码之前。

file_wrapper对象将存在(堆栈上(,但它不会绑定到变量f

不管我们的程序多么小心,中断会触发我们的资源警告吗?

>>> import dis
>>> dis.dis(test)
2           0 LOAD_CONST               0 (None)
2 STORE_FAST               0 (f)
3           4 SETUP_FINALLY           44 (to 50)
4           6 LOAD_GLOBAL              0 (file_wrapper)
8 LOAD_GLOBAL              1 (sys)
10 LOAD_ATTR                2 (stdin)
12 LOAD_ATTR                3 (fileno)
14 CALL_FUNCTION            1
16 STORE_FAST               0 (f)
...

是的,可能会发生这样的警告。没有什么可以阻止在CALL_FUNCTIONSTORE_FAST之间引发KeyboardInterrupt。

参见Nathan的博客文章,从";有些细节有时可以使我们的Python代码对KeyboardInterrupt"更加健壮";。从那时起,相关的Python代码略有更改,但这并不影响我们的情况。这些变化只解决了Nathan用自己的想法提到的某些局限性。

同样,KeyboardInterrupt也可能发生在file_wrapper.__init__()的第一行之前。在这种情况下,将在设置self.fd之前调用file_wrapper.__del__()__del__()将尝试读取self.fd,从而引发AttributeError异常。python标准库并没有试图阻止这种情况的发生。

KeyboardInterrupt是一个有用的破解方法,可以从单线程程序中获取回溯。特别是因为在启动程序后无法附加python调试器。它不是一个可靠的工具来编写一个可以中断的程序。

相关内容

  • 没有找到相关文章

最新更新