在Python 3中将字符串转换为字节的最佳方法是什么?

drkbr07n  于 2023-03-13  发布在  Python
关注(0)|答案(5)|浏览(170)

TypeError: 'str' does not support the buffer interface建议使用两种可能的方法将字符串转换为字节:

b = bytes(mystring, 'utf-8')

b = mystring.encode('utf-8')

哪种方法更像Python?
请参阅Convert bytes to a string了解相反的情况。

qvk1mo1f

qvk1mo1f1#

如果您查看bytes的文档,它会将您指向bytearray
字节数组([源[,编码[,错误]]])
返回一个新的字节数组。bytearray类型是一个可变的整数序列,范围为0〈= x〈256。它拥有可变序列类型中描述的可变序列的大多数常用方法,以及bytes类型拥有的大多数方法,请参见字节和字节数组方法。
可选的source参数可用于以几种不同的方式初始化数组:

如果是字符串,还必须给予编码(和可选的错误)参数;bytearray()然后使用str.encode()将字符串转换为字节。
如果是整数,数组将具有该大小,并将使用空字节初始化。
如果是符合缓冲区接口的对象,则使用该对象的只读缓冲区初始化字节数组。
如果它是一个可迭代对象,它必须是0〈= x〈256范围内的整数的可迭代对象,这些整数用作数组的初始内容。
如果没有参数,则创建大小为0的数组。

所以bytes可以做的不仅仅是编码字符串,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),而且对称性很好。

xytpbqjk

xytpbqjk2#

这比想象的要容易:

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'>
oug3syen

oug3syen3#

  • 绝对 * 最好的方法不是第2种,而是第3种。encode * 的第一个参数从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)
9gm1akwq

9gm1akwq4#

回答一个稍微不同的问题:
您有一个保存到str变量中的原始unicode序列:

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特定编码

h9a6wy2h

h9a6wy2h5#

Python 3的“内存视图”方式如何?
Memoryview是字节/字节数组和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]

不知道这是故意的还是一个错误,但它抓住了我!
该示例使用了UTF-16,有关编解码器的完整列表,请参见Python 3.10中的编解码器注册表

相关问题