2011-01-19 2 views
40

Использование StringIO в качестве строкового буфера происходит медленнее, чем использование списка в качестве буфера.Когда используется StringIO?

Когда используется StringIO?

from io import StringIO 


def meth1(string): 
    a = [] 
    for i in range(100): 
     a.append(string) 
    return ''.join(a) 

def meth2(string): 
    a = StringIO() 
    for i in range(100): 
     a.write(string) 
    return a.getvalue() 


if __name__ == '__main__': 
    from timeit import Timer 
    string = "This is test string" 
    print(Timer("meth1(string)", "from __main__ import meth1, string").timeit()) 
    print(Timer("meth2(string)", "from __main__ import meth2, string").timeit()) 

Результаты:

16.7872819901 
18.7160351276 
+1

Возможно, вы имеете в виду «Когда» вместо «Где» выше? –

ответ

23

Если измерить скорость, следует использовать cStringIO.

Из docs:

Модуль cStringIO обеспечивает интерфейс, подобный тому, что в модуле StringIO. Тяжелое использование Объектов StringIO.StringIO можно сделать более эффективным с помощью функции StringIO() вместо этого модуля.

Но точка StringIO должна быть файл-подобный объект, когда что-то ожидает, что такие, и вы не хотите использовать существующие файлы.

Редактировать: Я заметил, что вы используете from io import StringIO, поэтому вы, вероятно, находитесь на Python> = 3 или не менее 2.6. Отдельные StringIO и cStringIO ушли в Py3. Не знаю, какую реализацию они использовали для обеспечения io.StringIO. Также есть io.BytesIO.

+0

Попробуйте использовать 'cStringIO'. Результаты: Список: 17, cString: 33. – user225312

+3

io.StringIO - реализация C, если она существует на вашей платформе. Если он не использует резервную реализацию Python. Причина, по которой это медленнее, состоит в том, что он делает то, что ему не нужно, в первую очередь, для StringIO. –

31

Главное преимущество StringIO в том, что он может использоваться там, где ожидался файл. Так что вы можете сделать, например:

import sys 
import StringIO 

out = StringIO.StringIO() 

sys.stdout = out 

print "hi, I'm going out" 

sys.stdout = sys.__stdout__ 

print out.getvalue() 
+0

Может ли он использоваться с 'with' в python 2? Из того, что я вижу здесь, нет: http://bugs.python.org/issue1286 –

+0

@Mr_and_Mrs_D см. [Http://bugs.python.org/issue1286#msg176512](http://bugs.python.org/issue1286 # msg176512), в котором говорится, что он будет работать от 2,5 до. Что еще вам нужно, кровь на нем? : D –

+0

@MarkLawrence: нет, это не будет - перечитайте комментарий, который вы связали, - вам нужно перевернуть _your own_ context manager –

17

Ну, я не знаю, если я хотел бы назвать, что при использовании его в качестве «буфера», вы просто умножая строку в 100 раз, в двух сложных способов , Вот несложный способ:

def meth3(string): 
    return string * 100 

Если мы добавим, что к тесту:

if __name__ == '__main__': 

    from timeit import Timer 
    string = "This is test string" 
    # Make sure it all does the same: 
    assert(meth1(string) == meth3(string)) 
    assert(meth2(string) == meth3(string)) 
    print(Timer("meth1(string)", "from __main__ import meth1, string").timeit()) 
    print(Timer("meth2(string)", "from __main__ import meth2, string").timeit()) 
    print(Timer("meth3(string)", "from __main__ import meth3, string").timeit()) 

Это оказывается намного быстрее, в качестве бонуса:

21.0300650597 
22.4869811535 
0.811429977417 

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

Смежные вопросы