2013-02-10 62 views
1

我一直在寻找方法来清理python中的对象。 我目前使用pypy。在pypy中清理

我找到了一个网页和一个例子。

首先一个基本的例子:

class FooType(object): 
    def __init__(self, id): 
     self.id = id 
     print self.id, 'born' 

    def __del__(self): 
     print self.id, 'died' 


ft = FooType(1) 

这应该打印:

1出生 死亡1例

,但它只是打印 1出生

所以我的问题是:如何我可以在PyPy中清理任何东西吗?

+0

Python不会执行RAII; PyPy使用垃圾收集,并且绝不会保证运行。 – 2013-02-10 18:43:57

+0

取决于垃圾回收......解释器可能不会释放对象,直到它需要更多内存为止。 CPython使用引用计数并在没有更多引用时立即发布 – JBernardo 2013-02-10 18:44:11

+0

你甚至调用'del ft'吗? – Hidde 2013-02-10 18:45:57

回答

4

当您需要“清理”以确保在特定时间运行时,请使用context manager

class FooType(object): 
    def __init__(self, id): 
     self.id = id 
     print 'born' 
    def __enter__(self): 
     print 'entered' 
     return self 
    def __exit__(self, *exc): 
     print 'exited' 

with FooType(1) as ft: 
    pass # do something with ft 
4

用同样的方法,你应该它每隔Python实现,包括CPython的:通过明确管理代码的寿命,而不是依赖于自动内存管理和__del__

即使在CPython的,有一个以上的情况下__del__完全不称为,而相当多的情况下,这就是所谓的要晚得多比你想象的(例如,任何时候任何对象获取的引用赶上周期,这很容易发生)。这意味着它本质上是无用的,除了可能调试生命期问题(但是有内存分析器!),并且如果某些代码忽略了明确的清除,最后的手段。

通过明确清理,您避开了所有这些问题。有一种方法可以进行清理,并使客户代码在正确的时间调用它。上下文管理者可以更容易地处理异常,并且更易读。它通常也允许早于__del__清理,甚至如果引用计数“立即”呼叫__del__。例如,这个:

def parse_file(path): 
    f = open(path) 
    return parse(f.read()) # file stays open during parsing 

比这个w.r.t更糟糕。资源使用:

def parse_file(path): 
    with open(path) as f: 
     s = f.read() 
    # file is closed here 
    return parse(s) 

我也认为,这样的设计更清洁,因为它不会与裹着资源的寿命混淆资源包装对象的生命周期。有时候,让对象超越资源,甚至让它拥有新资源的所有权是有意义的。

2

在你的例子中,__del__没有被调用,但这只是因为你写的测试程序立即完成。 PyPy保证__del__在对象无法访问后的某段时间被调用,但只有当程序继续执行时才会调用该对象。因此,如果您在无限循环中执行ft = FooType(1),它也会在一段时间后打印died

正如其他答案所解释的那样,CPython并不能保证任何东西,但在简单的情况下(例如没有引用周期),它会立即可靠地调用__del__。不过,重点是你不应该严格依赖这一点。