class Package:
    def __init__(self):
        self.files = []

    # ...

    def __del__(self):
        for file in self.files:
            os.unlink(file)

__del__(self) 上面失败的一个AttributeError例外。我明白了 蟒蛇不能保证 存在着"全球变量"(部件的数据,在这方面?) 时 __del__() 被援引。如果是这种情况下,这是因为例外,如何确定对象的毁否正确?

有帮助吗?

解决方案

我会建议使用Python的with声明用于管理需要清理的资源。用一个明确的close()声明的问题是,你不必担心忘记的人在所有调用或忘记把它放在一个finally块,以防止资源泄漏时发生异常。

要使用with语句,创建一类具有以下方法:

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

在你上面的例子,你会使用

class Package:
    def __init__(self):
        self.files = []

    def __enter__(self):
        return self

    # ...

    def __exit__(self, exc_type, exc_value, traceback):
        for file in self.files:
            os.unlink(file)

然后,当有人想使用你的类,他们会做到以下几点:

with Package() as package_obj:
    # use package_obj

变量package_obj将型封装(它是由__enter__方法返回的值)的一个实例。其__exit__方法将被自动调用,而不管是否发生了异常。

您甚至可以采取这种做法更进了一步。在上面的例子中,有人仍然可以使用它的构造,而无需使用with子句实例化包装。你不希望这样的事情发生。您可以通过创建一个PackageResource类定义__enter____exit__方法解决这个问题。然后,包类将进行严格的__enter__方法内部定义并返回。这样一来,调用者永远无法实例化包装类,而无需使用with语句:

class PackageResource:
    def __enter__(self):
        class Package:
            ...
        self.package_obj = Package()
        return self.package_obj

    def __exit__(self, exc_type, exc_value, traceback):
        self.package_obj.cleanup()

您会使用此如下:

with PackageResource() as package_obj:
    # use package_obj

其他提示

的标准方法是使用 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...

作为一个附录 克林特*的答案, 你可以简化 PackageResource 使用 contextlib.contextmanager:

@contextlib.contextmanager
def packageResource():
    class Package:
        ...
    package = Package()
    yield package
    package.cleanup()

或者,虽然可能不如Python,你可以重写 Package.__new__:

class Package(object):
    def __new__(cls, *args, **kwargs):
        @contextlib.contextmanager
        def packageResource():
            # adapt arguments if superclass takes some!
            package = super(Package, cls).__new__(cls)
            package.__init__(*args, **kwargs)
            yield package
            package.cleanup()

    def __init__(self, *args, **kwargs):
        ...

和简单的使用 with Package(...) as package.

得到的东西短,名字你清理功能 close 和使用 contextlib.closing, ,在这种情况下可以使用未经修饰的 Package 类通过 with contextlib.closing(Package(...)) 或替代它的 __new__ 到简单的

class Package(object):
    def __new__(cls, *args, **kwargs):
        package = super(Package, cls).__new__(cls)
        package.__init__(*args, **kwargs)
        return contextlib.closing(package)

和这个构造是继承的,所以可以简单地继承的,例如

class SubPackage(Package):
    def close(self):
        pass

我不认为这是可能的__del__被调用之前被删除实例成员。我的猜测是,为您的特定AttributeError的原因是在其他地方(也许你错误地删除self.file其他地方)。

不过,由于有人指出,应该避免使用__del__。造成这种情况的主要原因是,随着__del__情况下不会被垃圾收集(当其引用计数为0时,他们才会被释放)。因此,如果你的情况下参与循环引用,他们将生活在内存中,只要应用程序运行。 (我可能是弄错了这一切,虽然,我不得不再次读取GC文档,但我宁愿相信这是这样的)。

我认为问题能够在 __init__ 如果有更多的代码显示?

__del__ 将被称为即使当 __init__ 没有被正确地执行或投掷了一个例外。

来源

一个更好的选择是使用 weakref.最后确定.看到的例子 终结的对象比较终结器与__德__()方法.

只是一个尝试换你的析构函数/ except语句,如果你的全局已配置的它不会抛出异常。

修改

尝试这种情况:

from weakref import proxy

class MyList(list): pass

class Package:
    def __init__(self):
        self.__del__.im_func.files = MyList([1,2,3,4])
        self.files = proxy(self.__del__.im_func.files)

    def __del__(self):
        print self.__del__.im_func.files

这将在东西的德尔功能是保证在呼叫时存在的文件列表。该weakref代理是为了防止Python或自己从删除self.files变量在某种程度上(如果它被删除,那么就不会影响到原来的文件列表)。如果不是,这是被删除即使有给变量更多的参考资料的情况下,那么你可以删除代理封装。

下面是一个最小的工作骨架:

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()

重要的:的返回自


如果你像我一样,俯瞰着return self部分(克林特·米勒的正确答案的),你会在这个无义盯着:

Traceback (most recent call last):
  File "tests/simplestpossible.py", line 17, in <module>                                                                                                                                                          
    fixture.method()                                                                                                                                                                                              
AttributeError: 'NoneType' object has no attribute 'method'

我花了半天这一点。希望它可以帮助下一个人。

看来,惯用的方法来做到这是提供一种方法close()(或类似),并且明确地调用它。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top