什么是Python字节串?

时间:2014-04-02 22:45:06

标签: python string bytestring

Python字节串是什么?

我能找到的主题是如何编码为bytestring或解码为asciiutf-8。我试图了解它是如何工作的。在普通的ASCII字符串中,它是一个数组或字符列表,每个字符代表一个0-255的ASCII值,这样你就知道这个数字代表什么字符。在Unicode中,它是字符的8或16字节表示,告诉你它是什么字符。

那么什么是字节串? Python如何知道哪些字符代表什么?它是如何在引擎盖下工作的?既然你可以打印甚至返回这些字符串,并且它会显示字符串表示,我就不太明白......

好的,所以我的观点是肯定在这里错过了。我被告知它是一个不可变的字节序列,没有任何特定的解释

字节序列..好吧,让我们说一个字节:
'a'.encode()返回b'a'

足够简单。为什么我能阅读 a

说我通过这样做得到 a 的ASCII值:
printf "%d" "'a"

返回 97 。好的,好的,ASCII字符 a 的整数值。如果我们将 97 解释为ASCII,例如在C char中,那么我们会得到字母a。很公平。如果我们将字节表示转换为位,我们得到:

01100001

2 ^ 0 + 2 ^ 5 + 2 ^ 6 = 97 。凉。

那么为什么'a'.encode()会返回b'a'而不是01100001? 如果它是没有特定的解释,那么它应该返回b'01100001'之类的内容吗? 似乎喜欢它像ASCII一样解释它。

有人提到它在字节字符串上调用__repr__,所以它以人类可读的形式显示。但是,即使我做了类似的事情:

with open('testbytestring.txt', 'wb') as f:
    f.write(b'helloworld')

仍然helloworld作为常规字符串插入到文件中,而不是作为字节序列...那么ASCII中的字节串是什么?

4 个答案:

答案 0 :(得分:24)

一个常见的误解是文本是ascii或utf8或cp1252,因此字节是文本。

文字只是文字,图像只是图像。将文本或图像存储到磁盘的问题是将数据编码为字节序列的问题。有许多方法可以将图像编码为字节:Jpeg,png,svg,以及编码文本的许多方法,ascii,utf8或cp1252。

一旦编码发生,字节只是字节。字节不再是图像,它们忘记了它们的意思;虽然图像格式解码器可以恢复该信息。字节同样忘记了以前的字母。实际上,字节不记得它们是图像还是文本。只有带外知识(文件名,媒体标题等)可以猜出这些字节应该是什么意思,甚至可能是错误的(如果数据损坏)

所以,在python(py3)中,我们有两种类型的东西可能看起来相似;对于文本,我们有str,它知道它的文本;它知道它应该是什么字母。它不知道可能是哪些字节,因为字母不是字节。我们还有bytestring,它不知道它是文本或图像还是任何其他类型的数据。

这两种类型在表面上是相似的,因为它们都是事物的序列,但它们是序列的东西是完全不同的。

在实现上,str作为UCS-?存储在内存中?是实现定义的,它可能是UCS4,UCS2或UCS1,具体取决于编译时选项以及表示的字符串中存在哪些代码点。


编辑“但为什么”?

有些看起来像文字的东西实际上是用其他术语定义的。一个很好的例子是世界上许多互联网协议。例如,HTTP是一种“文本”协议,实际上是使用RFC中常见的ABNF语法定义的。这些协议用八位字节表示,而不是字符,尽管也可以建议非正式编码:

  

2.3. Terminal Values

     

规则解析为一串终端值,有时称为
  字符。在ABNF中,一个字符只是一个非负整数   在某些上下文中,将值的特定映射(编码)转换为
  将指定字符集(例如ASCII)。

这种区别很重要,因为无法通过互联网发送文本,您唯一能做的就是发送字节。说“文本但是'foo'编码”使格式变得更加复杂,因为客户端和服务器现在需要以某种方式自己找出编码业务,希望以同样的方式,因为它们必须最终以字节形式传递数据无论如何。这是双重无用的,因为无论如何这些协议很少涉及文本处理,并且只是实现者的便利。服务器所有者和最终用户都不会对阅读单词Transfer-Encoding: chunked感兴趣,只要服务器和浏览器都能正确理解它。

相比之下,在处理文本时,您并不关心它是如何编码的。您可以任何方式表达“HeävyMëtalÜmlaüts”,除了“HeδvyMλtalάmlaόts”


因此,不同的类型可以让您说“此值”表示“文本”或“字节”。

答案 1 :(得分:17)

Python 知道如何表示字节串。这就是重点。

当您将值为97的字符输出到几乎任何输出窗口时,您将获得字符' a'但这不是实施的一部分;它恰好是本地真实的东西。如果您想要编码,则不要使用bytestring。如果你使用bytestring,你就没有编码。

关于.txt文件的文章表明你误解了发生了什么。你看,纯文本文件也没有编码。它们只是一系列字节。这些字节由文本编辑器翻译成字母,但不能保证在所有中打开文件的其他人会看到与你一样的东西,如果你偏离常见的ASCII字符集。

答案 2 :(得分:3)

顾名思义,Python3 bytestring(或简称为str in Python 2.7)是一个 bytes 的字符串。并且,正如其他人所指出的那样,它是不可改变的。

它与Python3截然不同 str(或更具描述性的,Python 2.7中的unicode) 字符串的抽象 unicode字符(又名UTF-32,尽管Python3在底层添加了花哨的压缩以减少类似于UTF-8的实际内存占用,甚至可能以更一般的方式)。

基本上有三种方式可以解释"这些字节。您可以查看元素的数值,如下所示:

>>> ord(b'Hello'[0])  # Python 2.7 str
72
>>> b'Hello'[0]  # Python 3 bytestring
72

或者你可以告诉Python向终端(或文件,设备,套接字等)发送一个或多个元素为8位字符,如下所示:

>>> print b'Hello'[0] # Python 2.7 str
H
>>> import sys
>>> sys.stdout.buffer.write(b'Hello'[0:1]) and None; print() # Python 3 bytestring
H

正如杰克暗示的那样,在后一种情况下,它是你的终端解释 角色,而不是Python。

最后,正如您在自己的研究中所看到的,您还可以使用 Python 来解释bytestring。例如,您可以在Python 2.7中构建一个这样的抽象unicode对象:

>>> u1234 = unicode(b'\xe1\x88\xb4', 'utf-8')
>>> u1234
u'\u1234'
>>> type(u1234)
<type 'unicode'>
>>> len(u1234)
1
>>> 

或者在Python 3中这样:

>>> u1234 = str(b'\xe1\x88\xb4', 'utf-8')
>>> '\\u%04x' % ord(u1234)
\u1234
>>> type(u1234)
<class 'str'>
>>> len(u1234)
1

但是如果你不想要它,unicode抽象不会自动发生。 bytestring的要点是你可以直接得到字节。即使在上面的Python2.7示例中:

>>> len(b'\xe1\x88\xb4')
3
>>> b'\xe1\x88\xb4'[0]
'\xe1'

您还可以使用bytestring做其他精彩的事情,比如知道它们是否适合文件中的保留空间,直接通过套接字发送它们,正确计算HTTP content-length字段,并避免Python Bug 8260。简而言之,在处理数据并以字节存储时使用bytestring

答案 3 :(得分:0)

字节对象是单字节的不可变序列。 docs对它们是什么以及如何使用它们有很好的解释。