TypeError: 'str' does not support the buffer interface 建议使用两种可能的方法将字符串转换为字节:
b = bytes(mystring, 'utf-8')
b = mystring.encode('utf-8')
哪种方法更 Pythonic?
bytes(item, "utf8")
就足够了,因为显式比隐式更好,所以... str.encode( )
默认默认为字节,使您更多 Unicode-zen 但更少 Explicit-Zen。 “共同”也不是我喜欢遵循的术语。此外,bytes(item, "utf8")
更像 str()
和 b"string"
符号。如果我很菜鸟无法理解您的原因,我深表歉意。谢谢你。
encode()
没有调用 bytes()
,反之亦然。当然这不是很明显,这就是我问这个问题的原因。
如果您查看 bytes
的文档,它会将您指向 bytearray
:
bytearray([source[, encoding[, errors]]]) 返回一个新的字节数组。 bytearray 类型是 0 <= x < 256 范围内的可变整数序列。它具有可变序列的大多数常用方法,在可变序列类型中描述,以及字节类型具有的大多数方法,请参见字节和字节数组方法。可选的源参数可用于以几种不同的方式初始化数组:如果是字符串,则还必须提供编码(以及可选的错误)参数; bytearray() 然后使用 str.encode() 将字符串转换为字节。如果它是一个整数,则该数组将具有该大小,并将使用空字节进行初始化。如果是符合缓冲区接口的对象,将使用该对象的只读缓冲区来初始化字节数组。如果是可迭代的,则必须是 0 <= x < 256 范围内的整数的可迭代,用作数组的初始内容。如果没有参数,则会创建一个大小为 0 的数组。
所以 bytes
可以做的不仅仅是对字符串进行编码。它是 Pythonic,它允许您使用任何有意义的源参数类型调用构造函数。
对于字符串的编码,我认为 some_string.encode(encoding)
比使用构造函数更 Pythonic,因为它是最自我记录的——“获取这个字符串并用这个编码对其进行编码”比 bytes(some_string, encoding)
更清晰——没有使用构造函数时的显式动词。
我检查了 Python 源代码。如果您使用 CPython 将 unicode 字符串传递给 bytes
,它会调用 PyUnicode_AsEncodedString,即 encode
的实现;因此,如果您自己调用 encode
,您只是跳过了一个间接级别。
另外,请参阅 Serdalis 的评论 - unicode_string.encode(encoding)
也更 Pythonic,因为它的逆是 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'>
obj.method()
语法而不是 cls.method(obj)
语法,即使用 bytestring = unicode_text.encode(encoding)
和 unicode_text = bytestring.decode(encoding)
。
self
作为第一个参数
encode
作为字符串上的绑定方法。这个答案建议您改为调用未绑定的方法并将字符串传递给它。这是答案中唯一的新信息,而且是错误的。
绝对最好的方法不是第 2 种,而是第 3 种。自 Python 3.0 以来,encode
默认为 '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)
'\u00012345'*10000
。在我的笔记本电脑上都需要 28.8us;额外的 50ns 可能会在舍入误差中丢失。当然,这是一个非常极端的例子——但是 'abc'
在相反的方向上同样极端。
'utf-8'
参数是首选参数。但是您已经明确表明,放弃参数会更快。这使得这是一个很好的答案,即使它不是最好的答案。
int(s, 10)
;-)
回答一个稍微不同的问题:
您有一系列原始 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 3 'memoryview' 方式怎么样。
Memoryview 是 byte/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]
不知道这是故意的还是错误的,但它抓住了我!
该示例使用 UTF-16,有关编解码器的完整列表,请参阅 Codec registry in Python 3.10
unicode_string.encode(encoding)
也与bytearray.decode(encoding)
很好地匹配。bytearray
在您需要可变对象时使用。简单的str
↔bytes
转换不需要它。bytearray
无关,只是bytes
的文档没有提供详细信息,他们只是说“这是bytearray
的不可变版本”,所以我必须从那里引用。byte_string.decode('latin-1')
之类的东西,因为utf-8
不涵盖 0x00 到 0xFF (0-255) 的整个范围,查看 python docs 了解更多信息。tl;dr
会有所帮助