2009-12-02 23 views
31

我的印象是,文件對象立即關閉時,他們的引用計數命中0,因此該行:文件對象在其引用計數爲零時是否自動關閉?

foo = open('foo').read() 

會得到你的文件的內容,並立即關閉文件。但是,在閱讀Is close() necessary when using iterator on a Python file object的答案之後,我得到的印象是這種情況沒有發生,並且對文件對象調用.close()總是需要

上面的行是否執行我認爲正在執行的操作,即使執行了,是Pythonic要做的事情嗎?

+1

你問的是Python的文件對象或操作系統級別的底層文件的對象? OS層與Python層分開。你在問什麼? – 2009-12-02 18:10:19

+1

我會歡迎解釋在兩個級別發生的事情。更具體地說,我想知道是否編寫該代碼行可能會導致我的應用程序出現問題。我假定Python何時關閉了底層對象被釋放的文件對象。 – 2009-12-02 18:22:41

回答

26

答案在您提供的鏈接中。當它破壞的文件對象

垃圾收集器將關閉文件,但:

  • 你真的沒有當它發生了控制。

    雖然CPython使用引用計數來確定性地釋放資源 (因此您可以預測何時將銷燬對象),但其他版本不必這樣做。 例如,Jython或IronPython都使用JVM和.NET垃圾收集器,只有在需要恢復內存時纔會釋放(並終止)對象,並且可能不會爲某些對象執行此操作,直到程序結束。 即使對於CPython,GC算法也可能在將來發生變化,因爲參考計數 效率不高。

  • 如果在文件對象銷燬時關閉文件時拋出異常,您無法對此做任何事情,因爲您不知道。

+1

因此,我可以推斷,在一般意義上,依賴於垃圾收集如何在我使用的Python版本中實現的細節是一個糟糕的想法,而不是Pythonic,因此這就是爲什麼我的代碼行在問題中是不正確的? – 2009-12-02 18:28:25

+1

@Brent:它不一定是不正確的(如果你__decide__取決於你的實現的具體行爲)。 我不知道Pythonic ;-)。 但是在任何託管環境中依靠垃圾收集器(調整爲釋放內存)來清理其他資源是錯誤的方向。 當然,如果它只是簡短的腳本,並且您只是簡單地讀取文件(就像在您的示例中那樣),讓GC甚至OS關閉該文件即可。 – 2009-12-02 18:37:59

23

如果你想可以肯定,我會寫這樣的代碼:

from __future__ import with_statement 

with open('foo') as f: 
    foo = f.read() 

這樣一來,你的文件關閉如預期,甚至有例外。


很久以後:這裏是一些代碼import dis顯示編譯器如何對待不同的這些。

>>> def foo(filename): 
...  with open(filename) as f: 
...   return f.read() 
... 
>>> def bar(filename): 
...  return open(filename).read() 
... 
>>> from dis import dis 
>>> 
>>> dis(foo) 
    2   0 LOAD_GLOBAL    0 (open) 
       3 LOAD_FAST    0 (filename) 
       6 CALL_FUNCTION   1 
       9 DUP_TOP    
      10 LOAD_ATTR    1 (__exit__) 
      13 ROT_TWO    
      14 LOAD_ATTR    2 (__enter__) 
      17 CALL_FUNCTION   0 
      20 STORE_FAST    1 (_[1]) 
      23 SETUP_FINALLY   23 (to 49) 
      26 LOAD_FAST    1 (_[1]) 
      29 DELETE_FAST    1 (_[1]) 
      32 STORE_FAST    2 (f) 

    3   35 LOAD_FAST    2 (f) 
      38 LOAD_ATTR    3 (read) 
      41 CALL_FUNCTION   0 
      44 RETURN_VALUE   
      45 POP_BLOCK   
      46 LOAD_CONST    0 (None) 
     >> 49 WITH_CLEANUP   
      50 END_FINALLY   
      51 LOAD_CONST    0 (None) 
      54 RETURN_VALUE   
>>> dis(bar) 
    2   0 LOAD_GLOBAL    0 (open) 
       3 LOAD_FAST    0 (filename) 
       6 CALL_FUNCTION   1 
       9 LOAD_ATTR    1 (read) 
      12 CALL_FUNCTION   0 
      15 RETURN_VALUE 
+1

我明白,但我具體問是否代碼做我認爲它做或不。如果不是,它是做什麼的,如果是的話,這是正確的方式嗎? – 2009-12-02 18:02:40

+1

正如@Edward Loper和@tomekszpakowicz所說,發生的事情將取決於實現,因此「代碼是否執行我認爲它的作用」取決於它在哪裏運行。我提供的解決方案與實施無關。 – hughdbrown 2009-12-02 19:44:12

+3

+1。 – dbn 2012-11-19 23:23:10

1

不,Python的優化刪除未使用的對象,所以它可能永遠不會(在退出時它會清除確定在腳本結束時)關閉文件。 @ hughdbrown指出了很好的解決方案。

相關問題