python - modulenotfounderror - Confundido acerca de StringIO, cStringIO y ByteIO
string argument expected, got ''bytes'' (1)
He buscado en Google y también busco en SO la diferencia entre estos módulos de búfer. Sin embargo, todavía no entiendo muy bien y creo que algunas de las publicaciones que leí están desactualizadas.
En Python 2.7.11, descargué un archivo binario de un formato específico usando r = requests.get(url)
. Luego pasé StringIO.StringIO(r.content)
, cStringIO.StringIO(r.content)
y io.BytesIO(r.content)
a una función diseñada para analizar el contenido.
Todos estos tres métodos están disponibles. Quiero decir, incluso si el archivo es binario, todavía es posible utilizar StringIO
. ¿Por qué?
Otra cosa es con respecto a su eficiencia.
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
Como se ilustra arriba, cStringIO > StringIO > BytesIO
.
Encontré que alguien mencionó que io.BytesIO
siempre hace una copia nueva que cuesta más tiempo. Pero también hay algunas publicaciones que indican que esto se solucionó en versiones posteriores de Python.
Entonces, ¿puede alguien hacer una comparación exhaustiva entre estos IO
, tanto en Python 2.xy 3.x?
Algunas de las referencias que encontré:
- https://trac.edgewall.org/ticket/12046
io.StringIO requiere una cadena Unicode. io.BytesIO requiere una cadena de bytes. StringIO.StringIO permite unicode o una cadena de bytes. cStringIO.StringIO requiere una cadena codificada como una cadena de bytes.
Pero cStringIO.StringIO(''abc'')
no cStringIO.StringIO(''abc'')
ningún error.
https://review.openstack.org/#/c/286926/1
La clase StringIO es la clase incorrecta que se usa para esto, especialmente considerando que la subunidad v2 es binaria y no una cadena.
http://comments.gmane.org/gmane.comp.python.devel/148717
cStringIO.StringIO (b''data '') no copió los datos, mientras que io.BytesIO (b''data'') hace una copia (incluso si los datos no se modifican más adelante).
Hay un parche de corrección en esta publicación en 2014.
- Un montón de mensajes de SO no enumerados aquí.
Aquí están los resultados de Python 2.7 para el ejemplo de 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
En cuanto a 2.7, cStringIO.StringIO
y StringIO.StringIO
son mucho más eficientes que io
.
Debe usar io.StringIO
o io.BytesIO
, dependiendo de si sus datos son binarios, tanto en python 2 como en 3, para la compatibilidad hacia adelante (esto es todo lo que 3 tiene para ofrecer).
Aquí hay una mejor prueba (para python 2 y 3), que no incluye los costos de conversión de numpy a 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
Y entonces:
import io
%timeit io.StringIO(u_data)
%timeit io.StringIO(b_data)
%timeit io.BytesIO(u_data)
%timeit io.BytesIO(b_data)
En Python 2, también puedes probar:
import StringIO, cStringIO
%timeit cStringIO.StringIO(u_data)
%timeit cStringIO.StringIO(b_data)
%timeit StringIO.StringIO(u_data)
%timeit StringIO.StringIO(b_data)
Algunos de estos se estrellarán, quejándose de personajes no ascii
Resultados de 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
Resultados de Python 2.7 (ejecutar en una máquina diferente):
>>> %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