2011-04-18 36 views
8

考慮下面的示例代碼在第二次初始化一個對象時,爲什麼__init__在__del__之前被調用?

class A: 
    def __init__(self, i): 
     self.i = i 
     print("Initializing object {}".format(self.i)) 

    def __del__(self): 
     print("Deleting object {}".format(self.i)) 

for i in [1, 2]: 
    a = A(i) 

創建對象中的循環是爲了確保將要創建的新的目的之前,A的析構函數被調用。但顯然會發生以下情況:

初始化對象1

初始化對象2

刪除對象1

刪除對象2

爲什麼對象1的析構函數只新對象初始化後調用?這是一種預期的行爲嗎?我知道for循環在Python中沒有自己的作用域。例如,在C++中,1的析構函數肯定會在對象2的構造函數之前被調用(至少如果對象是在循環中聲明的)。

在我的程序中,我想確保在創建新對象之前刪除舊對象。除了在for循環結束時顯式刪除a之外,是否還有其他可能性?

在此先感謝。

+0

如果將循環更改爲超過'[1,2,3]',則會發生有趣的事情。 – kennytm 2011-04-18 12:38:23

+1

這將是一個很好的面試問題。 – pajton 2011-04-18 12:39:02

+4

回覆最後一段:你不想那樣做。因爲你不能(GC是非確定性的,而refcounting是一個實現細節),並且你不需要。如果您有資源需要處理,請使用上下文管理器('with'語句)或添加一個像.close()這樣的方法,並確保調用它。 – delnan 2011-04-18 13:08:00

回答

11

創建第二個對象發生在名稱被反彈並且第一個對象被丟棄之前。

  1. 第一個A被實例化。
  2. a被綁定。
  3. 第二個A被實例化。
  4. a被反彈,第一個A被處置。
  5. 程序結束,第二個A被處置。
+0

感謝您的快速和詳細的答案!我應該使用'del'來確認先前的實例是否被刪除? – 2011-04-18 12:40:35

+0

是不是這個實現細節? – 2011-04-18 12:43:15

+0

你說得對。讓我這樣說:我想在A類的定義中沒有辦法實現這一點。 – 2011-04-18 12:48:17

9

在規劃生命週期依賴關係時,不能依賴垃圾收集器的實現細節。你需要明確地這樣或那樣做。

上下文管理器彈簧介意,例如:

from contextlib import contextmanager 

@contextmanager 
def deleting(obj): 
    try: 
     yield 
    finally: 
     del(obj) 

class A: 
    def __init__(self, i): 
     self.i = i 
     print("Initializing object {}".format(self.i)) 

    def __del__(self): 
     print("Deleting object {}".format(self.i)) 

for i in [1,2]: 
    with deleting(A(i)) as obj: 
     pass 

print 

for i in [1,2]: 
    a = A(i) 

這將產生以下輸出:

Initializing object 1 
Deleting object 1 
Initializing object 2 
Deleting object 2 

Initializing object 1 
Initializing object 2 
Deleting object 1 
Deleting object 2 
+0

非常感謝你的詳細解答 – 2011-04-18 17:20:48

0

假設要被定義爲它的最終值的對象時退出循環,請不要在for循環的end處明確刪除該對象,在循環的開始處這樣做,如下所示:

class A: 
    def __init__(self, i): 
     self.i = i 
     print("Initializing object {}".format(self.i)) 

    def __del__(self): 
     print("Deleting object {}".format(self.i)) 

for i in [1, 2, 3]: 
    a = None 
    a = A(i) 

,打印:

Initializing object 1 
Deleting object 1 
Initializing object 2 
Deleting object 2 
Initializing object 3 
Deleting object 3 

(注:Ignatio是正確的,爲什麼它的工作原理它的工作方式,但KennyTM是正確的,那就是,使之更加明顯發生了什麼,你應該做它至少通過循環三次。)

相關問題