class Package:
def __init__(self):
self.files = []
# ...
def __del__(self):
for file in self.files:
os.unlink(file)
上面的__del__(self)失败,出现AttributeError异常。我理解当调用__del__()时,Python不保证存在“全局变量”(在此上下文中是成员数据?)如果是这种情况,这是异常的原因,我如何确保对象销毁正确?
标准的方法是使用atexit.register:
# package.py
import atexit
import os
class Package:
def __init__(self):
self.files = []
atexit.register(self.cleanup)
def cleanup(self):
print("Running cleanup...")
for file in self.files:
print("Unlinking file: {}".format(file))
# os.unlink(file)
但是您应该记住,这将保存所有已创建的Package实例,直到Python终止。
演示使用上述代码保存为package.py:
$ python
>>> from package import *
>>> p = Package()
>>> q = Package()
>>> q.files = ['a', 'b', 'c']
>>> quit()
Running cleanup...
Unlinking file: a
Unlinking file: b
Unlinking file: c
Running cleanup...
atexit。在ostrakach的回答中已经提到过,寄存器是标准的方式。
但是,必须注意的是,不能依赖于对象可能被删除的顺序,如下例所示。
import atexit
class A(object):
def __init__(self, val):
self.val = val
atexit.register(self.hello)
def hello(self):
print(self.val)
def hello2():
a = A(10)
hello2()
a = A(20)
在这里,顺序似乎是合法的,因为它与创建对象的顺序相反,程序给出的输出如下:
20
10
然而,在一个较大的程序中,当python的垃圾收集启动超出其生命周期的对象时,将首先被销毁。
一个好主意是将两种方法结合起来。
实现用于显式生命周期处理的上下文管理器。以及句柄清理,以防用户忘记它或不方便使用with语句。这最好由weakref.finalize来完成。
这是很多图书馆实际做的。根据严重程度,你可以发出警告。
它保证只被调用一次,所以在之前的任何时候调用它都是安全的。
import os
from typing import List
import weakref
class Package:
def __init__(self):
self.files = []
self._finalizer = weakref.finalize(self, self._cleanup_files, self.files)
@staticmethod
def _cleanup_files(files: List):
for file in files:
os.unlink(file)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self._finalizer()
weakref。Finalize返回一个可调用的终结器对象,该对象将在obj被垃圾收集时被调用。与普通的弱引用不同,终结器将始终存在,直到引用对象被收集,从而极大地简化了生命周期管理。”
不像atexit。寄存器对象在解释器关闭之前不会保存在内存中。
不像物体。__del__ weakref。Finalize保证在解释器关闭时被调用。所以更安全。
下面是一个最小的工作框架:
class SkeletonFixture:
def __init__(self):
pass
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pass
def method(self):
pass
with SkeletonFixture() as fixture:
fixture.method()
重要:返回自我
如果你像我一样,忽略了(克林特·米勒正确答案中的)“回归自我”部分,你将会看到下面这段废话:
Traceback (most recent call last):
File "tests/simplestpossible.py", line 17, in <module>
fixture.method()
AttributeError: 'NoneType' object has no attribute 'method'
希望它能帮助到下一个人。