2016-02-23 23 views
9

में चंकिंग बाइट्स (स्ट्रिंग्स नहीं) यह मेरी अपेक्षा से अधिक कठिन हो रहा है।पायथन 2 और 3

data = b'abcdefghijklmnopqrstuvwxyz' 

मैं n बाइट्स की मात्रा में इस डेटा पढ़ना चाहते हैं: मैं एक बाइट स्ट्रिंग है। अजगर 2 के तहत, इस itertools प्रलेखन से grouper नुस्खा करने के लिए एक मामूली संशोधन का उपयोग कर तुच्छ है:

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)) 
जगह में इस के साथ

, मैं कॉल कर सकते हैं:

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

और मिलती है:

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

पायथन 3 के तहत, यह ट्रिकियर हो जाता है। grouper समारोह लिखा के रूप में बस के ऊपर गिर जाता है:

>>> 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 

और इस वजह से अजगर 3, में आप एक bytestring से अधिक पुनरावृति जब (जैसे b'foo'), आप बल्कि बाइट्स की एक सूची से, पूर्णांकों की एक सूची प्राप्त:

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

अजगर 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)) 

का उपयोग करना है कि, मैं क मिलता है पर मैं चाहता हूँ:

>>> 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'] 

लेकिन (! जाहिर है) अजगर 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

@ एंटी हैपाला, उस सूचक के लिए धन्यवाद। – larsks

उत्तर

3

Funcy (एक पुस्तकालय विभिन्न उपयोगी उपयोगिताओं, पेशकश समर्थन दोनों अजगर 2 और 3) करता है कि वास्तव में यह एक chunks function प्रदान करता है:

>>> 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 

वैकल्पिक रूप से, आप एक सरल (अपने कार्यक्रम में इस के कार्यान्वयन संगत शामिल हो सकते हैं पाइथन 2 दोनों के साथ।7 और 3):

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

यह वही (कम से कम अपने डेटा के लिए व्यवहार करती है; Funcy के chunks भी iterators साथ काम करता है, यह करता है):

>>> 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

इसे छोटा करने के लिए: हां, फन्सी इटेटेटर के साथ काम करता है, लेकिन यह सवाल से 'grouper' के समान काम करता है। यदि ओपी का डेटा एक इटरेटर/स्ट्रीम है, तो फंसी समाधान नहीं है। – vaultah

+0

ठीक है, लेकिन स्रोत आपके फ़ंक्शन 'चंक' में पुनरावर्तनीय नहीं हो सकता – vlk

2

का उपयोग bytesbytearray साथ के लिए काम करेगा दोनों अगर आपके स्ट्रिंग लंबाई एन से विभाज्य था या आप 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:

01,235,
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'] 
संबंधित मुद्दे