什么是Python字节串?

ant*_*ter 38 python string bytestring

什么是Python字节串?

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

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

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

一个字节序列..好吧,让我们说一个字节:
'a'.encode()返回b'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__了bytestring,所以它以人类可读的形式显示.但是,即使我做了类似的事情:

with open('testbytestring.txt', 'wb') as f:
    f.write(b'helloworld')
Run Code Online (Sandbox Code Playgroud)

它将仍然插入helloworld作为一个普通字符串到文件,而不是一个字节序列...所以是ASCII字节字符串?

Sin*_*ion 26

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

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

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

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

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

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


编辑"但为什么"?

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

2.3.终端价值

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

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

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


因此,不同的类型为您提供了一种方式来说"此值"表示"文本"或"字节".

  • 解释器调用魔术`__repr __()`函数,为您提供bytestring的可读表示.`__repr __()`被定义为返回一个字符串,因此它通过将bytestring视为ASCII或UTF-8来提供可能有意义的人字符串.这并不意味着底层字节串必然代表ASCII或看起来像一个字符串.地图不是领土. (8认同)
  • 让我重复一遍,`bytestring`*表示*不可变的字节序列,不暗示任何特定的解释,如文本或其他,而`str`*表示*unicode代码点的不可变序列,而不暗示任何特定的二进制编码.每个python文字看起来相似的事实只是一个方便. (3认同)
  • 只有人类才能将“b'Hello World”识别为文本。另一方面,`b'GIF89a\x01\x00\x01\x00\x80\x01\x00\xff\xff\xff\x00\x00\x00!\xf9\x04\x01\n\x00\x01\x00 ,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02L\x01\x00;'` 根本不是文本。两者都不能使用某些 win32 api 所期望的“utf16le”编码进行解码。 (2认同)

Jac*_*ley 23

Python 知道如何表示字节串.这才是重点.

当您将值为97的字符输出到几乎任何输出窗口时,您将获得字符'a',但这不是实现的一部分; 这恰好是本地真实的事情.如果需要编码,则不要使用bytestring.如果使用bytestring,则表示没有编码.

你关于.txt文件的文章表明你误解了发生了什么.你看,纯文本文件也没有编码.它们只是一系列字节.这些字节得到通过文本编辑器转换成字母,但不能保证所有别人打开你的文件会看到同样的事情,你,如果你流浪组共用的ASCII字符之外.

  • TLDR - 对我来说清楚的基本问题是文本编辑器、python 解释器(使用 `__repr__`)等,解释 `ASCII` 中的字节串(假设没有指定编码)以潜在地表示对用户有意义的东西. (2认同)

per*_*oud 9

顾名思义,Python 2/3 bytes(或 Python 2.7 中的 a )是一个bytesstr字符串。而且,正如其他人指出的那样,它是一成不变的。

\n

它与 Python 3 str(或者更具体地说,Python 2.7 中的 a )不同,后者是抽象Unicodeunicode字符的字符串(又名UTF-32,尽管 Python\xc2\xa03 在底层添加了奇特的压缩以减少实际内存足迹类似于 UTF-8,甚至可能以更通用的方式)。

\n

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

\n
>>> ord(b\'Hello\'[0])  # Python 2.7 str\n72\n>>> b\'Hello\'[0]  # Python 3 bytestring\n72\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
>>> print b\'Hello\'[0] # Python 2.7 str or bytes\nH\n>>> import sys\n>>> sys.stdout.buffer.write(b\'Hello\'[0:1]) and None; print() # Python 3 bytes\nH\n
Run Code Online (Sandbox Code Playgroud)\n

正如 Jack 所暗示的,在后一种情况下,是你的终端解释字符,而不是 Python。

\n

最后,正如您在自己的研究中所看到的,您还可以让Python解释bytes. 例如,您可以unicode在 Python 2.7 中构造一个像这样的抽象对象:

\n
>>> u1234 = unicode(b\'\\xe1\\x88\\xb4\', \'utf-8\')\n>>> print u1234.encode(\'utf-8\') # if terminal supports UTF-8\n\xe1\x88\xb4\n>>> u1234\nu\'\\u1234\'\n>>> print (\'%04x\' % ord(u1234))\n1234\n>>> type(u1234)\n<type \'unicode\'>\n>>> len(u1234)\n1\n>>>\n
Run Code Online (Sandbox Code Playgroud)\n

或者像 Python 3 中这样:

\n
>>> u1234 = str(b\'\\xe1\\x88\\xb4\', \'utf-8\')\n>>> print (u1234) # if terminal supports UTF-8 AND python auto-infers\n\xe1\x88\xb4\n>>> u1234.encode(\'unicode-escape\')\nb\'\\\\u1234\'\n>>> print (\'%04x\' % ord(u1234))\n1234\n>>> type(u1234)\n<class \'str\'>\n>>> len(u1234)\n1\n
Run Code Online (Sandbox Code Playgroud)\n

(而且我确信 Python\xc2\xa02.7 和 Python3 之间围绕字节串、字符串和 Unicode 的语法改动量与 Python\xc2\xa02.7 的持续流行有关。我想当 Python \xc2\xa03 被发明,他们还没有意识到一切都会变成 UTF-8,因此所有关于抽象的大惊小怪都是不必要的)。

\n

但是如果您不希望的话,Unicode 抽象不会自动发生。a 的要点bytes是你可以直接获取字节。即使您的字符串恰好是 UTF-8 序列,您仍然可以访问序列中的字节:

\n
>>> len(b\'\\xe1\\x88\\xb4\')\n3\n>>> b\'\\xe1\\x88\\xb4\'[0]\n\'\\xe1\'\n
Run Code Online (Sandbox Code Playgroud)\n

这在 Python\xc2\xa02.7 和 Python\xc2\xa03 中都有效,区别在于在 Python\xc2\xa02.7 中你有stror bytes,而在 Python3 中你有bytes

\n

您还可以使用 做其他奇妙的事情bytes,例如了解它们是否适合文件中的保留空间、直接通过套接字发送它们、content-length正确计算 HTTP 字段以及避免Python Bug 8260。简而言之,bytes当您的数据以字节为单位进行处理和存储时使用。

\n