Lee*_*Lee 22 python bytesio stringio cstringio
我用google搜索并在SO上搜索这些缓冲模块之间的区别.但是,我仍然不太了解,我认为我读到的一些帖子已经过时了.
在Python 2.7.11中,我使用了下载了特定格式的二进制文件r = requests.get(url).然后我通过StringIO.StringIO(r.content),cStringIO.StringIO(r.content)并io.BytesIO(r.content)设计用于解析内容的功能.
所有这三种方法都可用.我的意思是,即使文件是二进制文件,它仍然可以使用StringIO.为什么?
另一件事是他们的效率.
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
Run Code Online (Sandbox Code Playgroud)
如上图所示cStringIO > StringIO > BytesIO.
我发现有人提到io.BytesIO总是制作一个新的副本,花费更多的时间.但也有一些帖子提到这在以后的Python版本中得到修复.
那么,IO在最新的Python 2.x和3.x中,是否有人可以对这些s 进行彻底的比较?
我找到的一些参考文献:
io.StringIO需要一个unicode字符串.io.BytesIO需要一个字节字符串.StringIO.StringIO允许使用unicode或bytes字符串.cStringIO.StringIO需要一个编码为字节字符串的字符串.
但cStringIO.StringIO('abc')不会引起任何错误.
https://review.openstack.org/#/c/286926/1
StringIO类是用于此的错误类,特别是考虑到子单元v2是二进制而不是字符串.
http://comments.gmane.org/gmane.comp.python.devel/148717
当io.BytesIO(b'data')复制时,cStringIO.StringIO(b'data')没有复制数据(即使以后没有修改数据).
2014年这篇文章中有一个修补补丁.
以下是Eric的示例中的Python 2.7结果
%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
Run Code Online (Sandbox Code Playgroud)
至于2.7,cStringIO.StringIO并且StringIO.StringIO效率要高得多io.
Eri*_*ric 19
您应该在python 2和3中使用io.StringIO或unicode取决于您的数据是否为二进制,以实现向前兼容性(这是所有3必须提供的).
这是一个更好的测试(对于python 2和3),不包括从numpy到io.BytesIO/的转换成本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
Run Code Online (Sandbox Code Playgroud)
然后:
import io
%timeit io.StringIO(u_data)
%timeit io.StringIO(b_data)
%timeit io.BytesIO(u_data)
%timeit io.BytesIO(b_data)
Run Code Online (Sandbox Code Playgroud)
在python 2中,您还可以测试:
import StringIO, cStringIO
%timeit cStringIO.StringIO(u_data)
%timeit cStringIO.StringIO(b_data)
%timeit StringIO.StringIO(u_data)
%timeit StringIO.StringIO(b_data)
Run Code Online (Sandbox Code Playgroud)
其中一些会崩溃,抱怨非ascii字符
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
Run Code Online (Sandbox Code Playgroud)
Python 2.7结果(在不同的机器上运行):
>>> %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
Run Code Online (Sandbox Code Playgroud)
>>> %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
Run Code Online (Sandbox Code Playgroud)