TypeError: 'str'不支持buffer接口,建议使用两种方法将字符串转换为字节:
b = bytes(mystring, 'utf-8')
b = mystring.encode('utf-8')
哪种方法更python化?
TypeError: 'str'不支持buffer接口,建议使用两种方法将字符串转换为字节:
b = bytes(mystring, 'utf-8')
b = mystring.encode('utf-8')
哪种方法更python化?
如果你查看文档中的字节,它会指向bytearray:
Bytearray ([source[, encoding[, errors]]]) 返回一个新的字节数组。bytearray类型是一个范围为0 <= x < 256的可变整数序列。它具有可变序列的大多数常用方法,描述在可变序列类型中,以及字节类型具有的大多数方法,参见字节和字节数组方法。 可选的source参数可以用几种不同的方式初始化数组: 如果它是一个字符串,你还必须给出编码(和可选的错误)参数;Bytearray()然后使用str.encode()将字符串转换为字节。 如果它是一个整数,数组将具有该大小,并将初始化为空字节。 如果它是符合缓冲区接口的对象,则将使用该对象的只读缓冲区来初始化bytes数组。 如果它是一个可迭代对象,它必须是一个范围为0 <= x < 256的整数的可迭代对象,这些整数被用作数组的初始内容。 如果没有参数,则创建一个大小为0的数组。
字节可以做的远不止编码字符串。python允许你使用任何类型的源形参调用构造函数。
对于编码字符串,我认为some_string.encode(encoding)比使用构造函数更python化,因为它是最自我的记录——“获取此字符串并使用此编码对其进行编码”比bytes(some_string, encoding)更清楚——在使用构造函数时没有显式的谓词。
我检查了Python源代码。如果你使用CPython将unicode字符串传递给bytes,它会调用PyUnicode_AsEncodedString,这是encode;如果你自己调用encode,你就跳过了一层间接。
此外,参见Serdalis的注释——unicode_string.encode(encoding)也更符合python,因为它的逆是byte_string.decode(encoding),而且对称性很好。
这比想象的要简单:
my_str = "hello world"
my_str_as_bytes = str.encode(my_str)
print(type(my_str_as_bytes)) # ensure it is byte representation
my_decoded_str = my_str_as_bytes.decode()
print(type(my_decoded_str)) # ensure it is string representation
可以通过打印类型进行验证。参考下面的输出。
<class 'bytes'>
<class 'str'>
绝对最好的方法不是第二条,而是第三条。自Python 3.0以来,第一个默认编码为'utf-8'的参数。因此,最好的办法是
b = mystring.encode()
这也会更快,因为在C代码中默认参数的结果不是字符串“utf-8”,而是NULL,这检查起来要快得多!
以下是一些时间安排:
In [1]: %timeit -r 10 'abc'.encode('utf-8')
The slowest run took 38.07 times longer than the fastest.
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 183 ns per loop
In [2]: %timeit -r 10 'abc'.encode()
The slowest run took 27.34 times longer than the fastest.
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 137 ns per loop
尽管有警告,但在重复运行后,时间非常稳定——偏差只有2%左右。
使用不带参数的encode()不兼容Python 2,因为在Python 2中,默认字符编码是ASCII。
>>> 'äöä'.encode()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
回答一个稍微不同的问题:
你有一个原始的unicode序列被保存到一个str变量中:
s_str: str = "\x00\x01\x00\xc0\x01\x00\x00\x00\x04"
您需要能够获得该unicode的字节字面值(用于struct.unpack()等)。
s_bytes: bytes = b'\x00\x01\x00\xc0\x01\x00\x00\x00\x04'
解决方案:
s_new: bytes = bytes(s, encoding="raw_unicode_escape")
参考(向上滚动查看标准编码):
Python特定编码
Python 3的'memoryview'方式怎么样?
Memoryview是字节/bytearray和struct模块的一种大杂烩,有几个好处。
不仅限于文本和字节,处理16位和32位的单词 处理字节序 为链接的C/ c++函数和数据提供一个开销非常低的接口
最简单的例子,一个字节数组:
memoryview(b"some bytes").tolist()
[115, 111, 109, 101, 32, 98, 121, 116, 101, 115]
或用于unicode字符串(转换为字节数组)
memoryview(bytes("\u0075\u006e\u0069\u0063\u006f\u0064\u0065\u0020", "UTF-16")).tolist()
[255, 254, 117, 0, 110, 0, 105, 0, 99, 0, 111, 0, 100, 0, 101, 0, 32, 0]
#Another way to do the same
memoryview("\u0075\u006e\u0069\u0063\u006f\u0064\u0065\u0020".encode("UTF-16")).tolist()
[255, 254, 117, 0, 110, 0, 105, 0, 99, 0, 111, 0, 100, 0, 101, 0, 32, 0]
也许您需要的是文字而不是字节?
memoryview(bytes("\u0075\u006e\u0069\u0063\u006f\u0064\u0065\u0020", "UTF-16")).cast("H").tolist()
[65279, 117, 110, 105, 99, 111, 100, 101, 32]
memoryview(b"some more data").cast("L").tolist()
[1701670771, 1869422624, 538994034, 1635017060]
提醒一句。对于多个字节的数据,要小心对字节顺序的多重解释:
txt = "\u0075\u006e\u0069\u0063\u006f\u0064\u0065\u0020"
for order in ("", "BE", "LE"):
mv = memoryview(bytes(txt, f"UTF-16{order}"))
print(mv.cast("H").tolist())
[65279, 117, 110, 105, 99, 111, 100, 101, 32]
[29952, 28160, 26880, 25344, 28416, 25600, 25856, 8192]
[117, 110, 105, 99, 111, 100, 101, 32]
不确定这是故意的还是一个bug,但它抓住了我!!
示例使用UTF-16,完整的编解码器列表请参见Python 3.10中的编解码器注册表