2016-02-23 2 views
9

これは私が予想していたものよりもトリッキーになっています。Python 2と3のチャンクバイト(文字列ではない)

data = b'abcdefghijklmnopqrstuvwxyz' 

は私がn個バイトのチャンクでこのデータを読みたい:私はバイト文字列を持っています。 Pythonの2の下では、これはitertoolsドキュメントからgrouperレシピにマイナーな変更を使用して簡単です:

>>> list(grouper(data, 2)) 

をとget:代わりにこれにより

def grouper(iterable, n, fillvalue=None): 
    "Collect data into fixed-length chunks or blocks" 
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx 
    args = [iter(iterable)] * n 
    return (''.join(x) for x in izip_longest(fillvalue=fillvalue, *args)) 

、私が呼び出すことができます

['ab', 'cd', 'ef', 'gh', 'ij', 'kl', 'mn', 'op', 'qr', 'st', 'uv', 'wx', 'yz'] 

Python 3の場合、これは扱いにくくなります。

>>> list(grouper(data, 2)) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in <genexpr> 
TypeError: sequence item 0: expected str instance, int found 

をそして、あなたはバイト文字列(のようなb'foo')を反復はPython 3、で、あなたはむしろバイトのリストよりも、整数のリストを取得するためです。書かれ としてgrouper機能は、単に転倒します:

>>> list(b'foo') 
[102, 111, 111] 

のpython 3 bytes機能はここに役立ちます:

def grouper(iterable, n, fillvalue=None): 
    "Collect data into fixed-length chunks or blocks" 
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx 
    args = [iter(iterable)] * n 
    return (bytes(x) for x in izip_longest(fillvalue=fillvalue, *args)) 

を私はWHを得る、という使い方私が欲しい時:

>>> list(grouper(data, 2)) 
[b'ab', b'cd', b'ef', b'gh', b'ij', b'kl', b'mn', b'op', b'qr', b'st', b'uv', b'wx', b'yz'] 

しかし、(!のコース)Pythonの2の下bytes機能は 同じように動作しません。それは、strのためだけの別名だように結果:全く役に立たない

>>> list(grouper(data, 2)) 
["('a', 'b')", "('c', 'd')", "('e', 'f')", "('g', 'h')", "('i', 'j')", "('k', 'l')", "('m', 'n')", "('o', 'p')", "('q', 'r')", "('s', 't')", "('u', 'v')", "('w', 'x')", "('y', 'z')"] 

...。私は次のように書いてしまった:

def to_bytes(s): 
    if six.PY3: 
     return bytes(s) 
    else: 
     return ''.encode('utf-8').join(list(s)) 

def grouper(iterable, n, fillvalue=None): 
    "Collect data into fixed-length chunks or blocks" 
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx 
    args = [iter(iterable)] * n 
    return (to_bytes(x) for x in izip_longest(fillvalue=fillvalue, *args)) 

これは本当にそれを行う方法ですか?

+0

@AnttiHaapala、そのポインタのおかげです。 – larsks

答えて

3

Funcyまさにこの行いchunks function提供しています(、様々な便利なユーティリティを提供して支援の両方のPython 2と3ライブラリー):また

>>> import funcy 
>>> data = b'abcdefghijklmnopqrstuvwxyz' 
>>> list(funcy.chunks(6, data)) 
[b'abcdef', b'ghijkl', b'mnopqr', b'stuvwx', b'yz'] # Python 3 
['abcdef', 'ghijkl', 'mnopqr', 'stuvwx', 'yz']  # Python 2.7 

は、あなたのプログラムの中で、この単純な実装を含めることができます(互換性両方のPython 2で。7および3):

def chunked(size, source): 
    for i in range(0, len(source), size): 
     yield source[i:i+size] 

それは少なくとも、あなたのデータのために(同じ動作をします。Funcyのchunksもイテレータと連携し、これはそうではない):

>>> list(chunked(6, data)) 
[b'abcdef', b'ghijkl', b'mnopqr', b'stuvwx', b'yz'] # Python 3 
['abcdef', 'ghijkl', 'mnopqr', 'stuvwx', 'yz']  # Python 2.7 
+0

簡潔に言うと:はい、Funcyはイテレータで動作しますが、問題の 'grouper'と同様に動作します。 OPのデータがイテレータ/ストリームの場合、Funcyは解決策ではありません。 – vaultah

+0

Okですが、あなたの関数 'chunked'でソースを反復することはできません – vlk

2

bytearraybytesを使用するために働くでしょう両方のあなたの文字列の長さは、nで割り切れるだったか、fillvalueのような非空の文字列を渡す場合:

def grouper(iterable, n, fillvalue=None): 
    "Collect data into fixed-length chunks or blocks" 
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx 
    args = [iter(iterable)] * n 
    return ((bytes(bytearray(x))) for x in zip_longest(fillvalue=fillvalue, *args)) 

PY3:

In [20]: import sys 

In [21]: sys.version 
Out[21]: '3.4.3 (default, Oct 14 2015, 20:28:29) \n[GCC 4.8.4]' 

In [22]: print(list(grouper(data,2))) 
[b'ab', b'cd', b'ef', b'gh', b'ij', b'kl', b'mn', b'op', b'qr', b'st', b'uv', b'wx', b'yz'] 

PY2は:

def grouper(iterable, n, fillvalue=None): 
    "Collect data into fixed-length chunks or blocks" 
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx 
    args = [iter(iterable)] * n 
    return ((bytes(bytearray(filter(None, x)))) for x in zip_longest(fillvalue=fillvalue, *args)) 

任意の長さの文字列のために動作します:

In [6]: import sys 

In [7]: sys.version 
Out[7]: '2.7.6 (default, Jun 22 2015, 17:58:13) \n[GCC 4.8.2]' 

In [8]: print(list(grouper(data,2))) 
['ab', 'cd', 'ef', 'gh', 'ij', 'kl', 'mn', 'op', 'qr', 'st', 'uv', 'wx', 'yz'] 

は、あなたがそれらを除外することができ、空の文字列を渡した場合。

In [29]: print(list(grouper(data,4))) 
[b'abcd', b'efgh', b'ijkl', b'mnop', b'qrst', b'uvwx', b'yz'] 

In [30]: print(list(grouper(data,3))) 
[b'abc', b'def', b'ghi', b'jkl', b'mno', b'pqr', b'stu', b'vwx', b'yz'] 
関連する問題