python - 在 Python 2 和 3 中分块字节(不是字符串)

标签 python python-3.x python-2.x

事实证明这比我预期的要棘手。我有一个字节串:

data = b'abcdefghijklmnopqrstuvwxyz'

我想以 n 字节的 block 形式读取此数据。在 Python 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']

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

这是因为在 Python 3 中,当您迭代一个字节串(如 b'foo')时,您会得到一个整数列表,而不是一个字节列表:

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

使用它,我得到了我想要的:

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

这似乎可行,但真的是这样吗?

最佳答案

Funcy (一个提供各种有用实用程序的库,同时支持 Python 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

或者,您可以在您的程序中包含一个简单的实现(与 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

关于python - 在 Python 2 和 3 中分块字节(不是字符串),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35580801/

相关文章:

python - 将无聊的事情自动化第 6 章几乎完成的表打印机

sockets - Python 套接字多个客户端

python - 在Conda环境中安装包,但只能在Python中运行而不是在iPython中运行?

python - 在 macOS Sierra 上拖动 QTreeWidgetItem 时出现奇怪的行为

python - 根据指定列中的字符串值条目是否包含子字符串来分隔 pandas 数据框

python - 从 finditer 获取跨度和匹配

Python 尝试解析输入

python - 将带有内部空字符的 python2.7 字符串传递给 C++

python - 用列表列表屏蔽两列(Pandas df)

python - 无法创建着色器缓存条目 - 在通过其 Css 选择器定位元素时出错