(目录)
一、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]