Python 2.6和3中的bytes与bytearray区别

37

我正在尝试在Python 2.6中使用bytesbytearray。我不理解一些差异的原因。

bytes迭代器返回字符串:

for i in bytes(b"hi"):
    print(type(i))

输出:

<type 'str'>
<type 'str'>

然而,bytearray 迭代器会返回 int 类型:

for i in bytearray(b"hi"):
    print(type(i))

输出:

<type 'int'>
<type 'int'>

为什么会有差异?

我希望编写的代码可以在Python 3中表现良好。那么,在Python 3中情况是否相同?

5个回答

41

适用于(至少)Python 3.7

根据文档:

bytes 对象是由单个字节组成的不可变序列

bytearray 对象是 bytes 对象的可变对应项。

这就是关于 bytesbytearray 的基本信息。事实上,它们 相当互换,并被设计为足够灵活,以便在操作中混合使用而不会抛出错误。实际上,在 官方文档 中有一个专门的章节,介绍了 bytesbytearray api 之间的相似之处。

从文档中可以得到一些线索:

由于许多主要二进制协议都基于 ASCII 文本编码,因此 bytes 对象提供了几种仅在处理兼容 ASCII 数据时才有效的方法,并与字符串对象在许多其他方面密切相关。


32
在Python 2.6中,bytes仅是str的别名。这种"伪类型"被引入以[部分地]准备程序[和程序员!]转换/兼容Python 3.0,在那里str(它们是系统上的unicode)和bytes(它们是八位字节的数组,用于存储数据,但不是文本)有严格的语义和用法区别。
类似地,字符串文字的b前缀在2.6中无效,但它是程序中的一个有用标记,明确标志着程序员将字符串作为数据字符串而不是文本字符串。当程序移植到Py3k时,2to3转换器或类似实用程序可以使用此信息。
您可能需要检查此SO问题以获取其他信息。

更多信息请参见:http://docs.python.org/whatsnew/2.6.html#pep-3112-byte-literals和http://docs.python.org/3.1/library/stdtypes.html#sequence-types-str-bytes-bytearray-list-tuple-range - Ned Deily

8

TL;DR

python2.6+ bytes = python2.6+ str = python3.x bytes != python3.x str

python2.6+ bytearray = python3.x bytearray

python2.x unicode = python3.x str

长篇回答

自 Python 3.x 以来,bytesstr 在 Python 中的意义已经发生了变化。

首先简单回答你的问题,在 Python 2.6 中,bytes(b"hi") 是一个不可变的字节数组(8位或八进制数)。因此,每个byte 的类型就是byte,这与 Python 2.6+ 中的str 相同(但在 Python 3.x 中并非如此)。

bytearray(b"hi")是一个可变的字节数组。但是当你查询它的类型时,它是一个int,因为Python将bytearray的每个元素表示为0-255范围内的整数(8位整数的所有可能值)。然而,bytes数组的元素是该字节的ASCII值。

例如,在Python 2.6+中考虑:

>>> barr=bytearray(b'hi')
>>> bs=bytes(b'hi')
>>> barr[0] # python shows you an int value for the 8 bits 0110 1000
104 
>>> bs[0] # python shows you an ASCII value for the 8 bits 0110 1000
'h'
>>> chr(barr[0]) # chr converts 104 to its corresponding ASCII value
'h'
>>> bs[0]==chr(barr[0]) # python compares ASCII value of 1st byte of bs and ASCII value of integer represented by first byte of barr
True

现在Python 3.x有了完全不同的故事。正如您所猜测的那样,在Python2.6+中,为什么str文字会意味着byte是很奇怪的。这个答案解释了这个问题
在Python 3.x中,str是Unicode文本(以前只是字节数组,注意Unicode和字节是两个完全不同的东西)。bytearray是一个可变的字节数组,而bytes是一个不可变的字节数组。它们都有几乎相同的功能。现在,如果我在Python 3.x中再次运行上面的代码,这就是结果。在Python 3.x中。
>>> barr=bytearray(b'hi')
>>> bs=bytes(b'hi')
>>> barr[0]
104
>>> bs[0]
104
>>> bs[0]==barr[0] # bytes and bytearray are same thing in python 3.x
True

bytesbytearray在Python 3.x中是相同的,除了它们的可变性不同。

你可能会问:str发生了什么?在Python 3中,str被转换为Python 2中的unicode类型,并且unicode类型随后从Python 3中删除,因为它是多余的。

我想编写能够轻松转换到Python 3的代码。那么,在Python 3中情况是否相同?

这取决于你要做什么。你正在处理字节还是ASCII表示的字节?

如果你正在处理字节,那么我的建议是在Python 2中使用bytearray,它在Python 3中也是相同的。但是,如果对你很重要,你会失去不可变性。

如果你在处理ASCII或文本,则在Python 2中将字符串表示为u'hi',这在Python 3中具有相同的含义。在Python 2中,“u”具有特殊含义,它指示Python 2将字符串文字视为unicode类型。“u”在Python 3中没有意义,因为Python 3中所有字符串文字默认都是Unicode(在Python 3中令人困惑地称为str类型,在Python 2中称为unicode类型)。

3
我在Python 3.0上尝试了它。
在Python 3.0中,bytes迭代器返回的是int,而不像Python 2.6一样返回字符串:
for i in bytes(b"hi"):
    print(type(i))

给予:

<class 'int'>
<class 'int'>

bytearray 迭代器也返回 int 类型。


3
然而,bytes对象仍然是不可变的,像str一样;而bytearray可变并具有类似于list的接口。 - Mad Physicist

3

我不确定从哪个版本开始,但是 bytes 实际上是一个 str 类型,如果你执行 type(bytes(b"hi")),你会发现它的类型是 <type 'str'>

bytearray 是一个可变的字节数组,其中一个构造函数接受一个字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接