0
点赞
收藏
分享

微信扫一扫

python中的bytes和bytearray的区别

fbd4ffd0717b 05-03 15:00 阅读 9

(目录)

一、bytes类型(字节串)

字节序列bytes类型是一种不可变的类型。该类型的每一个元素是一个0-255的整数,也可以表示为十六进制形式0x00-0xFF。打印一个bytes对象有对应ASCII字符的字节会打印为对应的字符,没有对应可显字符的打印为形如\x2b的十六进制数,回车换行打印为\r\n。bytes类型类似str类型,可以使用相同的方法,比如索引,切片等,但仅限于读,不涉及写(不能原地修改in-place modification)。

print(list(map(hex, b'abc'))) # ['0x61', '0x62', '0x63']
print(list(map(bin, b'abc'))) # ['0b1100001', '0b1100010', '0b1100011']
print(bytes([123, 56, 37, 13, 10, 88])) # b'{8%\r\nX'

b'...'用于构造bytes对象的字面量——字节串。得到一个和字符串类似的==字节串常量==。

二、把字节解码成文本

需要使用bytes.decode()方法。

bseq = b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(bseq.decode("UTF-8"))
# 你好
  • 编码方式名称大小写不敏感,所以使用utf-8和使用UTF-8是一样的。
  • 使用b''字符串来创建bytes字面量
  • 字符\x在字节字符串中被转义,表示接下来的两个字符代表十六进制数。

decode()返回str对象。 在系统终端中正确地显示字符涉及PYTHONIOENCODING环境变量。 参考:https://docs.python.org/3.9/using/cmdline.html#envvar-PYTHONIOENCODING

PYTHONIOENCODING——用于控制向终端输出采用什么编码 If this is set before running the interpreter, it overrides the encoding used for stdin/stdout/stderr. 在Windows中设置环境变量: PYTHONIOENCODING=UTF-8 将改变Windows终端编码为UTF-8,并与python的默认输出字符编码保持一致,从而避免乱码的产生。 UTF-8编码的别名还有:utf-8,utf8,UTF8,UTF-8

三、把文本转成字节

需要使用str.encode()方法。

chars = "你好"
print(chars.encode("utf-8"))
# b'\xe4\xbd\xa0\xe5\xa5\xbd'

encode()返回bytes对象。 对于str.encode()和bytes.decode()可以不传递参数,此时会使用当前平台(终端)默认的编码格式,可以使用sys.getdefaultencoding()来获取默认的编码。

四、bytes与bytearray的区别

1. 为何要引入bytearray

bytes类型与str一样,是不可变的。因此,无法对bytes类型进行修改。如果涉及对字节序列进行修改的场景,则很不方便,需要生成新的字节对象bytes。而bytearray字节数组和列表类似,==是可变类型==,只是包含的元素是字节。这个类的构造方法接收bytes对象进行初始化,可以使用extgend()方法添加bytes对象到已存在的数组中,也可以修改bytearray中的元素。这省去了创建新对象的开销。 bytearray类型类似列表类型,可以使用相同的方法,比如索引的读写,extend(),切片的读写等,不仅可读,也可以写。

2. 修改bytearray对象

ba = bytearray(b'abcdefgh')
ba[4:6] = b'\x15\xa3'
print(ba) # bytearray(b'abcd\x15\xa3gh')

通过向bytearray()传入bytes对象可以将不可变的bytes字节序列构造成可变的bytearray对象。需要注意的是,想要修改bytearray中的单个元素,需要传入一个0-255的整数(或者\x表达的一字节,2位十六进制数),==如果试图传递字符,或者bytes对象将会抛出异常==。

ba = bytearray(b'abcdefgh')
ba[6] = ord('P')
print(ba) # bytearray(b'abcdefPh')

ba[6] = 'E'
# TypeError: 'str' object cannot be interpreted as an integer

ba[6] = b'E'
# TypeError: 'bytes' object cannot be interpreted as an integer

ba[6] = 256
# ValueError: byte must be in range(0, 256)

# 修改bytearray对象的元素只能使用0-255的整数
ba[6] = 88
ba[6] = int('58', 16)
ba[4:6] = [88, 89] # bytearray(b'abcdXYgh')
ba += b'XY'
ba.extend(b'^_^') # bytearray(b'abcdefgh^_^')
ba.extend([88, 89]) # bytearray(b'abcdefghXY')

# def extend(self, __iterable_of_ints: Iterable[SupportsIndex]) -> None

3. bytearray类型的所有常见写入方法

bytearray是可变类型,所有修改均为原地操作(In-place)。

# 索引赋值(支持单个字节的修改)
# 其中value为0-255之间的整数
bytearray_obj[index] = value
ba[0] = 100

# 片段赋值(切片赋值)
bytearray_obj[start:end] = bytes_or_iterable_of_ints(0, 256)
ba[1:3] = [200, 201]

# 通过索引或切片删除元素
del b[0]  # 删除第一个元素 
del b[1:3]  # 删除索引1-2的元素

# extend()
# 追加一个可迭代对象(如列表、元组或另一个bytearray)中的字节值
bytearray_obj.extend(iterable)
ba.extend((88, 89))
ba.extend([88, 89])
ba.extend(ba)

# append()
# 添加单个字节(一个整数,0-255)
bytearray_obj.append(byte)
ba.append(90) # bytearray(b'abcdefghXYZ')

# 在指定位置插入一个字节值
ba.insert(1, 90)

# 移除并返回指定位置的字节值(默认末尾)
ba = bytearray(b'abcdefgh')
removed = ba.pop(3)
print(ba, f'{removed:c}') # bytearray(b'abcefgh') d

# 移除第一个匹配的字节值
ba = bytearray(b'abcdefgh')
ba.remove(101)
print(ba.decode()) # abcdfgh

# 清空整个字节数组
ba.clear()

# 原地翻转字节数组顺序
ba = bytearray([1, 2, 3])
ba.reverse()
print(ba) # bytearray(b'\x03\x02\x01')

# 追加一个可迭代对象
ba += [6, 7]  # 等效于ba.extend([6,  7])

# 原地重复字节数组(n为整数)
ba = bytearray(b'abcdefgh')
ba *= 2
print(ba) # bytearray(b'abcdefghabcdefgh') 

# 大小端转换
import struct 
data = bytearray(struct.pack('>I',  0x12345678))  # 大端模式

Python中结合int.from_bytes() 和int.to_bytes() 修改bytearray

# 创建初始bytearray对象 
data = bytearray(b'\x01\x02\x03')

# 将整数转换为4字节大端序字节并追加 
num = 255
bytes_data = num.to_bytes(4, byteorder='big')
data += bytes_data  # 结果: bytearray(b'\x01\x02\x03\x00\x00\x00\xff')

# 验证转换结果 
print(int.from_bytes(data[-4:], byteorder='big'))  # 输出: 255

#---------------------------------------------------

# 初始化包含原始数据的bytearray
data = bytearray(b'\x00\x00\x00\x00')

# 将整数1000转换为4字节大端序并替换前4字节
new_num = 1000
data[:4] = new_num.to_bytes(4, byteorder='big')
# 结果: bytearray(b'\x00\x00\x03\xe8')

# 验证替换结果
print(int.from_bytes(data[:4], byteorder='big'))  # 输出: 1000

#---------------------------------------------------

# 创建空bytearray对象
data = bytearray()

# 插入多个整数(不同字节长度)
data.extend((123).to_bytes(2, 'little'))  # 2字节小端序
data.extend((456).to_bytes(4, 'big'))  # 4字节大端序
print(data)  # bytearray(b'{\x00\x00\x00\x01\xc8')

# 提取并验证值
val1 = int.from_bytes(data[0:2], 'little')
val2 = int.from_bytes(data[2:6], 'big')
print(val1, val2)  # 123 456

#---------------------------------------------------

# 定义包含多整数的原始字节数据 
raw_data = b'\x01\x00\x02\x00\x03\x00'

# 转换为bytearray并修改第2个整数(小端序)
data = bytearray(raw_data)
data[2:4] = (500).to_bytes(2, 'little')
print(data)  # bytearray(b'\x01\x00\xf4\x01\x03\x00')

# 解析所有整数 
nums = [
    int.from_bytes(data[0:2], 'little'),  # 1
    int.from_bytes(data[2:4], 'little'),  # 500
    int.from_bytes(data[4:6], 'little')  # 3
]
print(nums)  # 输出: [1, 500, 3]
举报

相关推荐

0 条评论