2009-12-02 16 views
31

Byłem pod wrażeniem, że obiekty plików są natychmiast zamknięte, kiedy ich liczy referencyjne hit 0, stąd wiersz:Czy obiekt pliku zamyka się automatycznie, gdy liczba jego odwołań jest równa zero?

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

dostanie ci zawartość pliku i natychmiast zamknij plik. Jednak po przeczytaniu odpowiedzi na Is close() necessary when using iterator on a Python file object mam wrażenie, że tak się nie dzieje i że wywołanie .close() na obiekcie pliku jest zawsze konieczne: .

Czy powyższa linia robi to, co myślę, że robi, a nawet jeśli tak, to czy jest to działanie Pythonica?

+1

Pytasz o obiektu pliku Python lub OS poziomu bazowego obiektu pliku? Warstwa systemu operacyjnego jest oddzielona od warstwy Pythona. O co pytasz? –

+1

Z zadowoleniem przyjmuję wyjaśnienie, co dzieje się na obu poziomach. Dokładniej, chciałbym wiedzieć, czy napisanie tej linii kodu potencjalnie spowoduje problemy w mojej aplikacji. Zakładałem, że gdy Python zamyka obiekt pliku, który jest również zwolniony, obiekt bazowy. –

Odpowiedz

26

Odpowiedź zawiera link, który podałeś.

Garbage collector zamyka plik, gdy niszczy obiekt pliku, ale:

  • naprawdę nie mieć kontrolę nad tym, kiedy to się stanie.

    Podczas gdy CPython używa licznika odwołań do deterministycznego udostępniania zasobów (dzięki czemu można przewidzieć, kiedy obiekt zostanie zniszczony) inne wersje nie muszą. Na przykład zarówno Jython, jak i IronPython używają JVM i .Ull garbage collector, który zwalnia (i finalizuje) obiekty tylko wtedy, gdy istnieje potrzeba odzyskania pamięci i może tego nie robić dla niektórych obiektów do końca programu. Nawet w przypadku CPython GC algorytm może się zmienić w przyszłości, ponieważ liczenie odniesienia nie jest zbyt wydajne.

  • jeśli zostanie zgłoszony wyjątek podczas zamykania pliku w celu zniszczenia obiektu, nie można naprawdę nic z tym zrobić, ponieważ nie będzie wiadomo.

+1

Więc, mogę wywnioskować w ogólnym sensie, że poleganie na specyfice sposobu, w jaki odśmiecanie jest zaimplementowane w wersji Pythona, której używam, jest złym pomysłem, a nie pytonem, i dlatego właśnie linia kodu mam w pytaniu jest niepoprawna? –

+1

@Brent: Niekoniecznie jest to niepoprawne (jeśli zależy ci na __decide__ od konkretnego zachowania). Nie wiem o Pythonie ;-). Ale w każdym zarządzanym środowisku, polegającym na czyszczeniu pamięci (dostrojone do wolnej pamięci), aby oczyścić inne zasoby, jest zły kierunek. Oczywiście, jeśli jest to tylko krótki skrypt _ i _ po prostu czytasz plik (jak w twoim przykładzie), możesz pozwolić GC lub nawet systemowi zamknąć plik. –

23

Jeśli chcesz mieć pewność, chciałbym napisać kod jak poniżej:

from __future__ import with_statement 

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

ten sposób, plik zamyka się zgodnie z oczekiwaniami, nawet z wyjątkami.


Znacznie później: Oto niektóre kodu z import dis pokazać jak kompilator traktuje je inaczej.

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

Rozumiem to, ale szczególnie pytam, czy kod robi to, co myślę, że robi, czy nie. Jeśli nie, to co robi, jeśli tak, to czy jest to właściwa droga? –

+1

Jako że @Edward Loper i @tomekszpakowicz twierdzą, że to, co się dzieje, będzie zależeć od implementacji, więc to, czy "kod będzie robił to, co myślę, że robi, czy nie" będzie zależeć od tego, gdzie jest uruchomiony. Dostarczone przeze mnie rozwiązanie jest niezależne od wdrożenia. – hughdbrown

+3

+1 za użycie dis. – dbn

1

Nie, Python zoptymalizować usuwanie nieużywanych przedmiotów, więc nigdy nie może zamknąć plik (OK na końcu skryptu na wyjeździe to będzie czyszczenia). @ hughdbrown wskazały dobre rozwiązanie.

9

Dla realizacji CPython pythona: tak, to jest gwarantowana być zamknięte, gdy jej Ilość referencyjna spadnie do zera.

Dla Pythona jako języka abstrakcyjnego (np. W tym Jython, IronPython itp.): nie, nie ma gwarancji, że zostanie zamknięty. W szczególności implementacja Pythona może nie korzystać z liczenia odwołań, ale używać innej formy GC.

Referencje:

Powiązane problemy