J'ai googlé et recherche également sur SO pour la différence entre ces modules de tampon. Cependant, je ne comprends toujours pas très bien et je pense que certains des messages que j'ai lus sont obsolètes.
Dans Python 2.7.11, j'ai téléchargé un fichier binaire d'un format spécifique en utilisant r = requests.get(url)
. Puis j'ai passé StringIO.StringIO(r.content)
, cStringIO.StringIO(r.content)
et io.BytesIO(r.content)
vers une fonction conçue pour analyser le contenu.
Ces trois méthodes sont disponibles. Je veux dire, même si le fichier est binaire, il est toujours possible d'utiliser StringIO
. Pourquoi?
Une autre chose concerne leur efficacité.
In [1]: import StringIO, cStringIO, io
In [2]: from numpy import random
In [3]: x = random.random(1000000)
In [4]: %timeit y = cStringIO.StringIO(x)
1000000 loops, best of 3: 736 ns per loop
In [5]: %timeit y = StringIO.StringIO(x)
1000 loops, best of 3: 283 µs per loop
In [6]: %timeit y = io.BytesIO(x)
1000 loops, best of 3: 1.26 ms per loop
Comme illustré ci-dessus, cStringIO > StringIO > BytesIO
.
J'ai trouvé que quelqu'un mentionnait que io.BytesIO
Fait toujours une nouvelle copie, ce qui coûte plus de temps. Mais il y a aussi quelques articles mentionnés qui ont été corrigés dans les versions ultérieures Python versions.
Alors, quelqu'un peut-il faire une comparaison approfondie entre ces IO
s, dans les deux derniers Python 2.x et 3.x?
Certaines des références que j'ai trouvées:
io.StringIO nécessite une chaîne unicode. io.BytesIO nécessite une chaîne d'octets. StringIO.StringIO autorise unicode ou une chaîne d'octets. cStringIO.StringIO nécessite une chaîne qui est codée comme une chaîne d'octets.
Mais cStringIO.StringIO('abc')
ne soulève aucune erreur.
https://review.openstack.org/#/c/286926/1
La classe StringIO est la mauvaise classe à utiliser pour cela, d'autant plus que la sous-unité v2 est binaire et non une chaîne.
http://comments.gmane.org/gmane.comp.python.devel/148717
cStringIO.StringIO (b'data ') n'a pas copié les données tandis que io.BytesIO (b'data') fait une copie (même si les données ne sont pas modifiées ultérieurement).
Il y a un correctif dans ce post en 2014.
Voici les résultats Python 2.7 pour l'exemple d'Eric
%timeit cStringIO.StringIO(u_data)
1000000 loops, best of 3: 488 ns per loop
%timeit cStringIO.StringIO(b_data)
1000000 loops, best of 3: 448 ns per loop
%timeit StringIO.StringIO(u_data)
1000000 loops, best of 3: 1.15 µs per loop
%timeit StringIO.StringIO(b_data)
1000000 loops, best of 3: 1.19 µs per loop
%timeit io.StringIO(u_data)
1000 loops, best of 3: 304 µs per loop
# %timeit io.StringIO(b_data)
# error
# %timeit io.BytesIO(u_data)
# error
%timeit io.BytesIO(b_data)
10000 loops, best of 3: 77.5 µs per loop
Quant à 2.7, cStringIO.StringIO
Et StringIO.StringIO
Sont bien plus efficaces que io
.
Tu devrais utiliser io.StringIO
pour la gestion des objets unicode
et io.BytesIO
pour gérer les objets bytes
dans les deux python 2 et 3, pour la compatibilité ascendante (c'est tout ce que 3 a à offrir).
Voici un meilleur test (pour python 2 et 3), qui n'inclut pas les coûts de conversion de numpy en str
/bytes
import numpy as np
import string
b_data = np.random.choice(list(string.printable), size=1000000).tobytes()
u_data = b_data.decode('ascii')
u_data = u'\u2603' + u_data[1:] # add a non-ascii character
Puis:
import io
%timeit io.StringIO(u_data)
%timeit io.StringIO(b_data)
%timeit io.BytesIO(u_data)
%timeit io.BytesIO(b_data)
Dans python 2, vous pouvez également tester:
import StringIO, cStringIO
%timeit cStringIO.StringIO(u_data)
%timeit cStringIO.StringIO(b_data)
%timeit StringIO.StringIO(u_data)
%timeit StringIO.StringIO(b_data)
Certains d'entre eux se bloqueront, se plaignant des caractères non ascii
Résultats Python 3.5:
>>> %timeit io.StringIO(u_data)
100 loops, best of 3: 8.61 ms per loop
>>> %timeit io.StringIO(b_data)
TypeError: initial_value must be str or None, not bytes
>>> %timeit io.BytesIO(u_data)
TypeError: a bytes-like object is required, not 'str'
>>> %timeit io.BytesIO(b_data)
The slowest run took 6.79 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 344 ns per loop
Résultats Python 2.7 (exécutés sur une autre machine):
>>> %timeit io.StringIO(u_data)
1000 loops, best of 3: 304 µs per loop
>>> %timeit io.StringIO(b_data)
TypeError: initial_value must be unicode or None, not str
>>> %timeit io.BytesIO(u_data)
TypeError: 'unicode' does not have the buffer interface
>>> %timeit io.BytesIO(b_data)
10000 loops, best of 3: 77.5 µs per loop
>>> %timeit cStringIO.StringIO(u_data)
UnicodeEncodeError: 'ascii' codec cant encode character u'\u2603' in position 0: ordinal not in range(128)
>>> %timeit cStringIO.StringIO(b_data)
1000000 loops, best of 3: 448 ns per loop
>>> %timeit StringIO.StringIO(u_data)
1000000 loops, best of 3: 1.15 µs per loop
>>> %timeit StringIO.StringIO(b_data)
1000000 loops, best of 3: 1.19 µs per loop