【问题标题】:Why does indexing bytes in Python 3 return an int instead of bytes?为什么 Python 3 中的索引字节返回一个 int 而不是字节?
【发布时间】:2020-05-12 01:42:20
【问题描述】:

试图理解为什么获取字节对象的索引会返回一个您无法解码的 int,但切片会返回一个您可以解码的字节对象。这似乎不直观。当你对一个字符串做同样的操作时,在字符串位置取一个索引仍然返回一个字符串。

在处理 Cryptopals 挑战时,我正在尝试遍历字节数组以对异或字符串进行频率分析,以计算纯文本字母的出现次数。我以为我可以执行以下操作,但我得到 'int' object has not attribute 'decode' 错误。从阅读 Python 文档来看,这是有道理的,字节数组是一个可变的整数序列,但是在解释器中进行测试时,我期待不同的行为。

str_a = bytearray(b'\x1b77316?x\x15\x1b\x7f+x413=x9x(7-6<x7>x:9;76')

for x in str_a:
    _ = x.decode('ascii').upper() 
    if _ in counts:
        counts[_] += 1

如果我将变量设置为单个字节,我可以在其上调用 decode()。我想我可以遍历字节字符串中的所有字节并以相同的方式解码(因此上面的循环)。但是,由于 r[0] 是一个 int,这不起作用。但是,如果我取 r[0:1],它会吗?我意识到我可以只调用 chr(r[0]),但我认为如果 r.decode() 有效,r[0].decode() 也应该有效。

>>> r = b'A'
>>> type(r)
<class 'bytes'>
>>> r.decode('ascii')
'A'
>>> r[0:1]
b'A'
>>> r[0:1].decode('ascii')
'A'
>>> type(r[0])
<class 'int'>
>>> r[0]
65
>>> r[0].decode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'decode'

字符串示例

>>> x = 'AB'
>>> type(x)
<class 'str'>
>>> x[0]
'A'
>>> type(x[0])
<class 'str'>

【问题讨论】:

  • 这似乎是 Python3 最不明智的设计决策之一。如果你想做位操作会发生什么?也许你必须使用 C++。

标签: python-3.x


【解决方案1】:

bytes 对象迭代为ints 的原因是因为它们在概念上是字节的静态数组——从 0 到 255 的整数(根据 PEP 358)——而不是交替编码的字符串。替代文本编码是一种常见的用例,但读取和写入任意二进制数据同样重要。

特别是关于str.encodebytes.decode,能够调用some_bytes[0].decode 不一定有意义,因为在许多编码中,字符可能被编码为多个字节。例如,b'a'.decode('utf-32') 失败,因为 UTF-32 每个字符使用四个字节。


围绕PEP 467 的讨论(其中建议添加bytes.iterbytes 等内容)可能会进一步了解bytes 的行为方式。

【讨论】:

  • 嗯。这很有意义。我才刚刚开始弄乱它并处理编码单个字节的数据。我没有从多字节的角度考虑它。谢谢!
【解决方案2】:

如您所见,bytes iterator generates integers not characters。您需要使用chrint 值转换为str 值。

import collections
import string

str_a = b"\x1b77316?x\x15\x1b\x7f+x413=x9x(7-6<x7>x:9;76"
count = collections.defaultdict(int)

for value in str_a:
    value = chr(value).upper()
    if value in string.ascii_uppercase:
        count[value] += 1

【讨论】:

  • 是的,我想我只是对为什么感到困惑。就像,这似乎与我的预期相反。我想如果我正在处理一个字节数组,其中的对象将是字节,我可以在其中的单个元素上调用字节方法。当您可以执行 b'A'.decode() 和 b'A'[0:1].decode() 而不是 b'A'[0].decode() 时,这会变得更加混乱。似乎它“破坏”了迭代器
  • PEP 358 也没有帮助。猜猜它就是这样。哦,好吧
猜你喜欢
  • 2011-06-07
  • 1970-01-01
  • 2014-09-24
  • 1970-01-01
  • 1970-01-01
  • 2011-06-13
  • 2023-03-28
  • 1970-01-01
相关资源
最近更新 更多