2012-03-15 19 views
24

Niektóre kodu:Czy muszę zrobić StringIO.close()?

import cStringIO 

def f(): 
    buffer = cStringIO.StringIO() 
    buffer.write('something') 
    return buffer.getvalue() 

documentation mówi:

StringIO.close(): Uwolnij bufor pamięci. Próba wykonania dalszych operacji z zamkniętym obiektem StringIO spowoduje zgłoszenie błędu ValueError.

Czy muszę wykonać buffer.close(), czy stanie się to automatycznie, gdy bufor wyjdzie poza zasięg i zostanie zebrany śmieci?

UPDATE:

Zrobiłem test:

import StringIO, weakref 

def handler(ref): 
    print 'Buffer died!' 

def f(): 
    buffer = StringIO.StringIO() 
    ref = weakref.ref(buffer, handler) 
    buffer.write('something') 
    return buffer.getvalue() 

print 'before f()' 
f() 
print 'after f()' 

Wynik:

[email protected]:~/projects$ python test.py 
before f() 
Buffer died! 
after f() 
[email protected]:~/projects$ 
+0

dlaczego nie wydrukować f() zamiast tylko nagiego f()? – mpag

Odpowiedz

12

Generalnie nadal lepiej jest zadzwonić pod numer close() lub użyć instrukcji with, ponieważ w szczególnych okolicznościach może wystąpić nieoczekiwane zachowanie. Na przykład expat-IncrementalParser wydaje się oczekiwać zamknięcia pliku lub nie zwróci ostatniej ciekawości analizowanego pliku XML, dopóki w niektórych rzadkich okolicznościach nie wystąpi przekroczenie limitu czasu.

Ale dla with -statement, który obsługuje zamknięcie dla Ciebie, trzeba użyć klasy StringIO od io -Modules, jak podano w komentarzu IVC.

To był poważny ból głowy w jakimś starszym skrypcie sax-parser, który rozwiązaliśmy poprzez ręczne zamknięcie StringIO.

Zamknięcie "poza zasięgiem" nie działa. Po prostu czekał na limit czasu.

+14

Poza tym, że StringIO i cStringIO w Py2 nie implementują protokołu menedżera kontekstu - tak, aby użyć go w instrukcji 'with', musisz zrobić' with contextlib.closing (StringIO()) jako bufor: '. Z drugiej strony, 'io.StringIO' Py3, * może * być użyte bezpośrednio w instrukcji' with'. – lvc

+3

'io.StringIO' implementuje protokół kontekstowego menedżera, ale nie wcześniejszy 2.6 patrz: http: //docs.python.org/release/2.6.7/library/io.htmlhighlight = io.stringio # io.IOBase' –

+2

Ah, nie zdawałem sobie sprawy, że moduł "io" istniał tak dawno temu. Dzięki za wskaźnik. Pozostaje jednak, że moduły 'StringIO.StringIO' i' cStringIO.StringIO' użyte w OP nie. Jestem nieco zaskoczony, że nie są one oznaczone jako przestarzałe w wersji 2.6/2.7 i że nie ma nawet zwykłej notatki w dokumentach 2.7, mówiących "te już nie istnieją w 3.x". – lvc

8

StringIO.close() jest tylko wygoda dla procedur, które mają na plikach jak i ewentualnie próbować zamknij je. Nie musisz robić tego sam.

+1

To nie jest wygoda, raczej konieczność. Bez tego kod zamykający obiekt podobny do pliku pękłby. –

+3

@Maxim: Jest to konieczne dla tego kodu. To wygoda dla klienta. –

11

Od źródła:

class StringIO: 
    ... 
    def close(self): 
     """Free the memory buffer. 
     """ 
     if not self.closed: 
      self.closed = True 
      del self.buf, self.pos 

Więc StringIO.close tylko uwalnia bufor pamięci skreślenie odniesień do StringIO.buf i StringIO.pos. Ale jeśli self jest zbiorem śmieci, jego atrybuty również zostaną zebrane, mając taki sam efekt jak StringIO.close.

3

Zostałem usunięty przy użyciu bloku try, aby go obsłużyć.

import cStringIO 

def f(): 
    buffer = cStringIO.StringIO() 
    try: 
     buffer.write('something') 
     return buffer.getvalue() 
    finally: 
     buffer.close() 
Powiązane problemy