在Python 3中将字符串转换为字节的最佳方法是什么?
TypeError: 'str' 不支持缓冲区接口 提出了两种将字符串转换为字节的方法:
b = bytes(mystring, 'utf-8')
b = mystring.encode('utf-8')
哪种方法更符合Python的风格呢?
查看 将字节转换为字符串 了解反向操作。
5 个回答
最好的方法其实不是前面提到的两种,而是第三种。从Python 3.0开始,encode
的第一个参数默认是'utf-8'
。所以最好的写法是:
b = mystring.encode()
这样做会更快,因为默认参数在C代码中并不是字符串"utf-8"
,而是NULL
,检查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)
其实这比大家想的要简单:
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'>
如果你查看 bytes
的文档,它会引导你去看 bytearray
:
bytearray([source[, encoding[, errors]]])
这个函数会返回一个新的字节数组。
bytearray
类型是一个可变的整数序列,范围是 0 到 255。它有很多常见的可变序列的方法,具体可以参考可变序列类型的相关内容,还有大部分bytes
类型的方法,详细信息可以查看字节和字节数组方法。可选的
source
参数可以用来以几种不同的方式初始化这个数组:如果
source
是一个字符串,你还必须提供编码(encoding
)和可选的错误处理(errors
)参数;这时bytearray()
会使用str.encode()
将字符串转换为字节。如果
source
是一个整数,数组的大小将是这个整数,并且会用空字节初始化。如果
source
是一个符合缓冲区接口的对象,字节数组将使用这个对象的只读缓冲区进行初始化。如果
source
是一个可迭代对象,它必须是一个整数的可迭代对象,范围是 0 到 255,这些整数将作为数组的初始内容。如果没有参数,将创建一个大小为 0 的数组。
所以 bytes
的功能远不止于编码字符串。它很符合 Python 的风格,允许你用任何合适的类型作为 source
参数来调用构造函数。
对于字符串的编码,我觉得 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)
,这种对称性很不错。