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


858

TypeError的答案中可以看出,有两种不同的方法可以将字符串转换为字节:'str'不支持缓冲区接口

以下哪种方法更好或更Pythonic?还是仅仅是个人喜好问题?

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

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

42
使用编码/解码更常见,也许更清晰。
Lennart Regebro 2011年

11
@LennartRegebro我解雇了。即使更常见,读“ bytes()”我也知道它在做什么,而encode()并没有让我觉得它正在编码为字节。
m3nda

2
@ erm3nda这是一个很好的理由来使用它,直到它确实这样的感觉,那么你是一步步接近到Unicode禅。
Lennart Regebro

3
@LennartRegebro我感觉很好,只需使用bytes(item, "utf8"),因为显式要好于隐式,所以... str.encode( )默默地默认为字节,使您的Unicode-zen更为丰富,但Explicit-Zen更少。同样,“通用”不是我喜欢遵循的术语。另外,,bytes(item, "utf8")更像是str()b"string"符号。如果我真不明白您的原因,我深表歉意。谢谢。
m3nda

4
@ erm3nda,如果您阅读了已接受的答案,您会发现encode()它没有调用bytes(),反之亦然。当然,这不是立即显而易见的,这就是为什么我问这个问题。
Mark Ransom

Answers:


570

如果您查看的文档bytes,它将指向bytearray

bytearray([源[,编码[,错误]]])

返回一个新的字节数组。字节数组类型是一个可变的整数序列,范围为0 <= x <256。它具有可变序列类型中介绍的大多数可变序列的常用方法,以及字节类型具有的大多数方法,请参见字节和。字节数组方法。

可选的source参数可以通过几种不同的方式用于初始化数组:

如果是字符串,则还必须提供编码(以及可选的错误)参数;然后,bytearray()使用str.encode()将字符串转换为字节。

如果它是整数,则数组将具有该大小,并将使用空字节初始化。

如果它是符合缓冲区接口的对象,则该对象的只读缓冲区将用于初始化bytes数组。

如果是可迭代的,则它必须是0 <= x <256范围内的整数的可迭代对象,这些整数用作数组的初始内容。

没有参数,将创建大小为0的数组。

所以 bytes除了编码字符串以外,还可以做更多的事情。这是Pythonic的用法,它允许您使用有意义的任何类型的源参数来调用构造函数。

对于编码字符串,我认为它some_string.encode(encoding)比使用构造函数更具Pythonic性,因为它是最易于记录的文档-“使用此字符串并使用此编码对其进行编码”比bytes(some_string, encoding) - -当您使用构造函数。

编辑:我检查了Python源。如果您将unicode字符串传递给bytes使用CPython,它将调用PyUnicode_AsEncodedString,它是encode; 的实现。因此,如果您自称,则只是跳过了间接级别encode

另外,请参见Serdalis的评论- unicode_string.encode(encoding)也是Python 风格的,因为它的反函数为byte_string.decode(encoding),对称性很好。


73
+1具有良好的论点和python文档引号。还可以unicode_string.encode(encoding)bytearray.decode(encoding)您希望返回字符串的时间很好地匹配。
Serdalis 2011年

6
bytearray在需要可变对象时使用。你不需要它简单strbytes转换。
hamstergene 2011年

8
@EugeneHomyakov这与bytearray文档bytes无关,只是没有提供详细信息,他们只是说“这是的不可变版本bytearray”,所以我必须从那里引用。
2011年

1
从仅仅是一种谨慎注意的Python果壳中的有关bytes使用字节类型整数参数的函数避免。在v2中,这将返回整数,该整数将转换为(byte)字符串,因为bytes是str的别名,而在v3中,它将返回包含给定数量的空字符的字节字符串。因此,例如,使用等效的b'\ x00'* 6代替v3表达式bytes(6),在每个版本中其工作方式均相同。
holdenweb

1
请注意,如果您尝试将二进制数据转换为字符串,则很可能需要使用诸如这样的方法,byte_string.decode('latin-1')因为utf-8它不能覆盖0x00到0xFF(0-255)的整个范围,请查看python 文档以获取相关信息更多信息。
iggy12345

345

比想像的要容易:

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

37
他知道该怎么做,只是在问哪种方法更好。请重新阅读问题。
13年

30
仅供参考:str.decode(bytes)对我不起作用(Python 3.3.3说“类型对象'str'没有属性'decode'”))我改用bytes.decode()
Mike

6
@Mike:使用obj.method()语法而不是cls.method(obj)语法,即使用bytestring = unicode_text.encode(encoding)unicode_text = bytestring.decode(encoding)
jfs

2
...例如,您不必要地创建一个未绑定的方法,然后将其self作为第一个参数传递给它
Antti Haapala

2
@KolobCanyon这个问题已经显示了正确的方法- encode在字符串上作为绑定方法调用。该答案建议您应该改为调用unbound方法,并将其传递给字符串。那是答案中唯一的新信息,这是错误的。
abarnert

144

绝对最好的办法既不是2,但第3位。自Python 3.0以来,第一个参数默认默认值。因此,最好的方法是encode 'utf-8'

b = mystring.encode()

这也将更快,因为默认参数的结果不是"utf-8"C代码中的字符串,而是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)

2
这里只有一个很大的差异,因为(a)字符串是纯ASCII的,这意味着内部存储已经是UTF-8版本,因此查找编解码器几乎是唯一涉及的成本,并且(b)字符串很小,因此即使您必须进行编码,也不会有太大区别。试试,例如'\u00012345'*10000。两者在我的笔记本电脑上的花费都是28.8us。舍入误差可能会使额外的50ns丢失。当然,这是一个非常极端的示例,但'abc'在相反方向上也是如此。
abarnert

@abarnert正确,但是即使如此,也没有理由将参数作为字符串传递。
Antti Haapala

据此,默认参数始终是做事的“绝对最佳方法”,对吗?如果这是关于讨论C代码的,那么这种速度分析可能会被夸大。用一种解释性的语言,它使我无语。
hmijail哀悼辞职者
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.