Python3:迭代二进制字符串将字符转换为整数

Ara*_*uma 2 python string iteration python-2.7 python-3.x

我觉得我在这里错过了一些微不足道的东西:

我最近跳到了 Python3(在 Eclipse 中使用 PyDev)。
我有一个计算熵值的项目,并包含以下代码:

data = b'NVGI\x19\x01\x10\x00'
seen = dict(((chr(x), 0) for x in range(0,256)))
for byte in data:
    seen[byte]+=1
Run Code Online (Sandbox Code Playgroud)

data 中的二进制字符串要长得多,但这足以用于演示目的。

对于 python3,此代码会导致 KeyError。对于 python2.7,这完全没有问题。

这是因为迭代data返回一个整数(在本例中为 78),而saw需要一个字符“N”。

奇怪的是,在 python2.7 中,相同的代码将产生预期的字符“N”。

我现在已经通过这样做来创可贴:

seen[ord(byte)] += 1
Run Code Online (Sandbox Code Playgroud)

有人可以尝试复制这个或告诉我哪里出了问题吗?

Wil*_*sem 5

因为在,二进制字符串的元素ints

的确:

>>> type(data[0])
<class 'int'>
Run Code Online (Sandbox Code Playgroud)

Python 3.0 的新增功能”文档中也对此进行了指定。

因此,您可以通过构建字典来解决问题,例如:

seen = dict(((x, 0) for x in range(0,256)))
Run Code Online (Sandbox Code Playgroud)

或者你可以用相反的方式来做:

data = b'NVGI\x19\x01\x10\x00'
seen = dict(((chr(x), 0) for x in range(0,256)))
for byte in data:
    seen[chr(byte)]+=1
Run Code Online (Sandbox Code Playgroud)

但更优雅的解决方案是简单地使用计数器:

from collections import Counter

result = Counter(data)
Run Code Online (Sandbox Code Playgroud)

生成:

>>> Counter(data)
Counter({16: 1, 1: 1, 86: 1, 25: 1, 73: 1, 71: 1, 78: 1, 0: 1})
Run Code Online (Sandbox Code Playgroud)

ACounter的子类dict,因此计数器支持所有字典操作。

如果您希望计数器包含string 值,您可以这样做:

result = Counter(chr(x) for x in data)
Run Code Online (Sandbox Code Playgroud)

这给出:

>>> Counter(chr(x) for x in data)
Counter({'\x00': 1, 'G': 1, 'I': 1, '\x01': 1, 'V': 1, 'N': 1, '\x10': 1, '\x19': 1})
Run Code Online (Sandbox Code Playgroud)

请注意,如果您在计数器中查询不存在的键,它将返回0。因此,您还可以节省内存,因为您不一定拥有所有 256 个值的计数。