从https://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface 的答案中可以看出,似乎有两种不同的方法可以将字符串转换为字节。
哪种方法会更好或更符合Pythonic的要求?还是说这只是一个个人偏好的问题?
b = bytes(mystring, 'utf-8')
b = mystring.encode('utf-8')
如果你看一下bytes
的文档,它指向[bytearray
](https://docs.python.org/3/library/functions.html#func-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向bytes
传递一个unicode字符串,它会调用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)
type(my_str_as_bytes) # ensure it is byte representation
my_decoded_str = my_str_as_bytes.decode()
type(my_decoded_str) # ensure it is string representation
绝对好的方法是这两个都不是,而是第三个。从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)