Python 3.3:访问字符串内部表示法?

Python 3.3:访问字符串内部表示法?,python,string,unicode,python-3.3,Python,String,Unicode,Python 3.3,在Python>=3.3中,为了帮助解决Unicode编码和解码问题,我希望能够从Python代码中检查存储在字符串中的实际内部数据。我该怎么做 有一个str.encode()方法,它返回字节表示,但通常这是由特定编解码器(由“encoding”参数选择)翻译的字节序列,而不是str对象中存储的实际原始字节 有一个“unicode_internal”编码选项,但它已被弃用,并且不清楚在3.3中,它是返回真实的内部数据(如何组织?),还是返回它的一些翻译 PEP 393描述了Unicode数据的内

在Python>=3.3中,为了帮助解决Unicode编码和解码问题,我希望能够从Python代码中检查存储在字符串中的实际内部数据。我该怎么做

有一个str.encode()方法,它返回字节表示,但通常这是由特定编解码器(由“encoding”参数选择)翻译的字节序列,而不是str对象中存储的实际原始字节

有一个“unicode_internal”编码选项,但它已被弃用,并且不清楚在3.3中,它是返回真实的内部数据(如何组织?),还是返回它的一些翻译

PEP 393描述了Unicode数据的内部结构,从中可以看出,从Python访问该数据需要报告字符串种类(1/2/4字节)、表示(ASCII/compact)以及包含字符串内容的字节数组(我认为其格式是ASCII、UCS1、2或4)

我还没有在Python中找到提供这种访问的str类型的方法

还有别的办法吗?也许是使用struct的聪明方法?还是公开这些字符串内部的C库

更新2014-03-13:

感谢所有回答了为什么不想访问字符串内部结构的人的建议。对于普通Python程序来说,这无疑是一个有效的建议

尽管如此,我的问题是:如何做到这一点

扩展基本原理:这是为了解决编码-解码问题,其中一个函数(可能在某些库中)创建并返回str,另一个函数(可能在某些其他库中)应该对该str执行某些操作

我想检查中间str的确切内容(即:我想将问题空间一分为二),这样做时不需要引入进一步的变量,即让一个或另一个python函数将数据转换为其他形式(如带转义序列的ASCII)

除其他原因外,我想知道确切的内部数据,以防另一个库实际对内部数据格式敏感。所说的库很可能是用C编写的,可以访问这些数据,并且处理不当

此外,事实上,str应该被视为一系列代码点,内部表示不受关注。但是,如果字符串处理中确实存在错误,我不想被它误导,如果没有,我希望相信没有。考虑到字符串库的复杂性,零bug将是一个相当大的成就


那么:如何检查字符串的内部结构呢?

Python中的Unicode字符串应该被视为Unicode代码点序列。如何在内部表示这一点对于编码和解码问题完全无关紧要

您可以通过对字符串的各个字符使用
ord()
函数来访问Unicode代码点的数值:

>>> list(map(ord, "abc €"))
[97, 98, 99, 32, 8364]

我不认为这对调试编码问题(或其他任何问题)特别有帮助,但它可能会澄清Unicode字符串在概念上是什么。

内部切换到更节省空间的Unicode值存储仅出于性能原因

因此,它们对unicode
str
值在Python代码中的编码和解码方式没有任何影响。从Python访问内部表示绝对没有意义。字符
A
存储为
41
4100
41000000
,具体取决于字符串中最高代码点所需的空间大小,但仍将以ASCII、拉丁语-1或UTF-8将其编码为
41

除非您正在编写一个必须处理这种内部表示的C扩展,否则绝对不需要担心Python实际上是如何存储数据的

要调试编码或解码问题,我将使用表示字符串,仅使用ASCII码点和Python字符串文字转义,或者可以使用将单个字符转换为每个码点的整数


对于字节值,还可以方便地将一系列字节快速转换为十六进制表示形式。

Python的内部字符串表示形式严格来说是一个内部实现细节,可能因Python的不同版本和操作系统而异。由于问题指定了Python版本号>=3.3,我将假设我们讨论的是CPython(1/2/4字节字符表示),并使用id()给出内存地址的CPython实现细节。下面使用Ubuntu19.10的系统CPython3.7.5

from ctypes import string_at
from sys import getsizeof
from binascii import hexlify
a = "ABCDE"
print(hexlify(string_at(id(a), getsizeof(a))))
产出:

b'0100000000000000c0988500000000000500000000000000625866dab454b033e
  50064016c006d010000000000000000414243444500'
你可以在十六进制的末尾看到“ABCDE”,从41到45递增。如果从Unicode代码点范围128-255将字符添加到该字符串中,例如0xA2处的分号“、ABCDE”,则该字符仍然可以用单个字节表示,因此这就是CPython所做的,尽管字符串前面的空行由于某种原因而增加:

b'0200000000000000c09885000000000006000000000000003b7ac7a960368ad4a
  4005a006501650200000000000000000000000000000000000000000000000000
  00000000000000a2414243444500'
如果将Unicode 255以上的字符添加到字符串中,例如0x153处的oe连字“œABCDE”,则整个字符串将切换为每个字符两个字节,其中“œ”表示小端“5301”,a表示“4100”,依此类推:

b'0200000000000000c0988500000000000600000000000000e50dd134c7e9b87ca
  83d22c59341424300000000000000000000000000000000000000000000000000
  000000000000005301410042004300440045000000'

内部表示如何帮助您解决编码或解码问题?在尝试确定内容时,我会坚持使用
ascii()
。除非您正在编写需要处理
str
类型内部的C扩展,否则绝对不需要处理内部C结构。这就像试图处理
dict
类型的内部哈希表;它与Python代码的编码或解码问题无关