2013-02-10 95 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__。不過,重點是你不應該嚴格依賴這一點。