Quand StringIO utilisé, par opposition à se joindre à une liste de chaînes?

StackOverflow https://stackoverflow.com/questions/4733693

  •  12-10-2019
  •  | 
  •  

Question

Utilisation StringIO comme tampon de chaîne est plus lent que d'utiliser la liste comme tampon.

Quand est StringIO utilisé?

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

Résultats:

16.7872819901
18.7160351276
Était-ce utile?

La solution

Si vous mesurez la vitesse, vous devez utiliser cStringIO.

De la docs :

  

Le module fournit une cStringIO   une interface similaire à celle de la   Module StringIO. Une utilisation intensive   objets StringIO.StringIO peuvent être   plus efficace en utilisant la fonction   StringIO () à partir de ce module à la place.

Mais le point de StringIO est d'être un fichier comme objet , quand quelque chose attend tel et vous ne voulez pas utiliser des fichiers réels.

Modifier J'ai remarqué que vous utilisez from io import StringIO, alors vous êtes probablement sur Python> = 3 ou au moins 2,6. La StringIO séparée et cStringIO sont partis en PY3. Je ne sais pas ce que la mise en œuvre qu'ils ont utilisé pour fournir le io.StringIO. Il est io.BytesIO aussi.

Autres conseils

Le principal avantage de StringIO est qu'il peut être utilisé là où un fichier était attendu. Ainsi, vous pouvez le faire par exemple (pour Python 2):

import sys
import StringIO

out = StringIO.StringIO()
sys.stdout = out
print "hi, I'm going out"
sys.stdout = sys.__stdout__
print out.getvalue()

Eh bien, je ne sais pas si je voudrais appeler l'utiliser comme un « tampon », vous êtes juste multiplierez une chaîne 100 fois, de deux façons compliquées. Voici une façon simple:

def meth3(string):
    return string * 100

Si l'on ajoute cela à votre test:

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

Il se révèle être beaucoup plus rapide en prime:

21.0300650597
22.4869811535
0.811429977417

Si vous voulez créer un bouquet de chaînes, puis les rejoindre, meth1 () est la bonne façon. Il n'y a pas de point par écrit à StringIO, ce qui est quelque chose de complètement différent, à savoir une chaîne avec un fichier comme l'interface flux.

Une autre approche basée sur l'approche Lennart Regebro. C'est plus rapide que la méthode de la liste (meth1)

def meth4(string):
    a = StringIO(string * 100)
    contents = a.getvalue()
    a.close()
    return contents

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())
    print(Timer("meth3(string)", "from __main__ import meth3, string").timeit())
    print(Timer("meth4(string)", "from __main__ import meth4, string").timeit())

Résultats (sec.):

  

METH1 = 7,731315963647944

     

METH2 = 9,609279402186985

     

meth3 = 0,26534052061106195

     

meth4 = 2,915035489152274

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top