30

これらのバッファモジュールの違いをグーグルで検索し、SOでも検索しました。しかし、私はまだよく理解していません。私が読んだ記事のいくつかは古くなっていると思います。

Python 2.7.11 では、特定の形式のバイナリ ファイルを を使用してダウンロードしましたr = requests.get(url)。次に、コンテンツを解析するために設計された関数にStringIO.StringIO(r.content), cStringIO.StringIO(r.content)andを渡しました。io.BytesIO(r.content)

これら 3 つの方法はすべて利用可能です。つまり、ファイルがバイナリであっても、StringIO. なんで?

もう1つのことは、それらの効率に関するものです。

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

上図のように、cStringIO > StringIO > BytesIO.

io.BytesIO常に新しいコピーを作成するため、より多くの時間がかかると誰かが言及しているのを見つけました。しかし、これが後の Python バージョンで修正されたという投稿もいくつかあります。

IOでは、最新の Python 2.x と 3.x の両方で、これらの s を完全に比較できる人はいますか?


私が見つけた参照の一部:

  • https://trac.edgewall.org/ticket/12046

    io.StringIO には Unicode 文字列が必要です。io.BytesIO にはバイト文字列が必要です。StringIO.StringIO は、Unicode またはバイト文字列のいずれかを許可します。cStringIO.StringIO には、バイト文字列としてエンコードされた文字列が必要です。

しかしcStringIO.StringIO('abc')、エラーは発生しません。

この投稿には 2014 年の修正パッチがあります。

  • ここにリストされていないSOの投稿がたくさんあります。

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

2.7 に関しては、cStringIO.StringIOStringIO.StringIOは よりもはるかに効率的ですio

4

1 に答える 1

25

前方互換性のために、オブジェクトの処理と Python 2 と 3 の両方でのオブジェクトの処理に使用する必要があります (これはすべて 3 が提供する必要がありますio.StringIO) 。unicodeio.BytesIObytes


numpy からstr/への変換コストを含まない、より良いテスト (python 2 および 3 用) を次に示します。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

その後:

import io
%timeit io.StringIO(u_data)
%timeit io.StringIO(b_data)
%timeit io.BytesIO(u_data)
%timeit io.BytesIO(b_data)

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)

これらのいくつかはクラッシュし、非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

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
>>> %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
于 2016-05-26T14:01:22.723 に答える