2012-03-15 2 views
24

Часть кода:Должен ли я делать StringIO.close()?

import cStringIO 

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

documentation говорит:

StringIO.close(): Освободить буфер памяти. Попытка сделать еще операции с закрытым объектом StringIO вызовут ValueError.

Должен ли я сделать buffer.close(), или это произойдет автоматически, когда буфер выходит из сферы действия и собирается ли мусор?

UPDATE:

Я сделал тест:

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()' 

Результат:

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

Почему бы не напечатать f(), а не только голый f()? – mpag

ответ

12

Как правило, лучше позвонить по телефону close() или использовать инструкцию with, поскольку в особых обстоятельствах может возникнуть непредвиденное поведение. Например, expat-IncrementalParser, похоже, ожидает, что файл будет закрыт или он не вернет последний лакомый кусочек анализируемого xml до тех пор, пока не произойдет тайм-аут в некоторых редких случаях.

Но для with -statement, который обрабатывает закрытие для вас, вы должны использовать StringIO класс от io -модулями, как указано в комментарии IVC.

Это была серьезная головная боль в каком-то унаследованном сценарии сакса-парсера, который мы решили, закрыв StringIO вручную.

«Вне пределов области действия» не работает. Он просто ждал предела ожидания.

+14

За исключением того, что StringIO и cStringIO в Py2 не реализуют протокол диспетчера контекста - поэтому, чтобы использовать его в '' '' '' '' '' '' '' '' '' '' '' ',' 'должно быть' with contextlib.closing (StringIO()) в качестве буфера: '. С другой стороны, 'iio.StringIO' Py3, * может * использоваться в' '' непосредственно. – lvc

+3

'io.StringIO' реализует протокол контекстного менеджера, но не до 2.6 см: http: //docs.python.org/release/2.6.7/library/io.htmlhighlight = io.stringio # io.IOBase' –

+2

А, я не понял, что модуль 'io' существовал так далеко. Спасибо за указатель. Однако остается, что модули 'StringIO.StringIO' и' cStringIO.StringIO', используемые в OP, не работают. На самом деле я немного удивлен, что они не отмечены как устаревшие в 2.6/2.7, и что в 2.7 документах нет даже обычной заметки, говорящей, что «они больше не существуют в 3.x». – lvc

8

StringIO.close() это просто удобство для подпрограмм, которые принимают файл, как и в конечном итоге попытаться закройте их. Нет необходимости делать это самостоятельно.

+1

Это не удобство, а необходимость. Без него будет нарушен код, который закрывает файл-подобный объект. –

+3

@Maxim: Это необходимость для этого кода. Это удобство для клиента. –

11

Из источника:

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

Так StringIO.close просто освобождает буфер памяти удаляемых ссылки на StringIO.buf и StringIO.pos. Но если self - это сбор мусора, его атрибуты также будут собирать мусор, имея тот же эффект, что и StringIO.close.

3

Я закончил с помощью блока try, чтобы обработать его.

import cStringIO 

def f(): 
    buffer = cStringIO.StringIO() 
    try: 
     buffer.write('something') 
     return buffer.getvalue() 
    finally: 
     buffer.close() 
Смежные вопросы