为什么 \x00 没有被 repr 转换为 \0

Why is \x00 not converted to \0 by repr

这里有一个关于 Python 的 repr 的有趣的奇怪之处:

制表符 \x09 表示为 \t。但是,此约定不适用于空终止符。

为什么\x00表示为\x00,而不是[=15=]

示例代码:

# Some facts to make sure we are on the same page
>>> '\x31' == '1'
True
>>> '\x09' == '\t'
True
>>> '\x00' == '[=10=]'
True

>>> x = '\x31'
>>> y = '\x09'
>>> z = '\x00'
>>> x
'1' # As Expected
>>> y
'\t' # Okay
>>> z
'\x00' # Inconsistent - why is this not [=10=]

简短的回答:因为这不是 使用的特定转义。字符串表示仅使用单字符转义 \\n\r\t,(当 " 和 [=存在 17=] 个字符),因为有针对这些字符的显式测试。

其余的要么被认为是可打印的并按原样包含,要么使用更长的转义序列包含(取决于 Python 版本和字符串类型,\xhh\uhhhh\Uhhhhhhhh,始终使用符合该值的 3 个选项中最短的一个。

此外,在生成 repr() 输出时,对于由空字节后跟从 '1' 到 [=23] 的 数字 组成的字符串=](所以 bytes([0x00, 0x49]),或 bytes([0x00, 0x4A]),等等),你不能只在输出中使用 [=26=] 而不必转义后面的数字。 '' 是单个八进制转义序列,与 '\x001' 不同,后者是两个字节。虽然强制输出始终使用三个八进制数字(例如 '[=29=]01')可能是一种解决方法,但坚持使用标准化、更简单的转义序列格式会更简单。向前扫描以查看下一个字符是否为八进制数字并切换输出样式只会产生令人困惑的输出(想象一下 SO 上的问题:'\x001''[=31=]Ol' 之间有什么区别? )

输出始终一致。除了单引号(可以与 '\' 一起出现,具体取决于 " 个字符的存在),Python 将始终使用 same给定代码点的转义序列样式

如果你想研究产生输出的代码,你可以在 Objects/unicodeobject.c unicode_repr() function 中找到 Python 3 str.__repr__ 实现,它使用

/* Escape quotes and backslashes */
if ((ch == quote) || (ch == '\')) {
    PyUnicode_WRITE(okind, odata, o++, '\');
    PyUnicode_WRITE(okind, odata, o++, ch);
    continue;
}


/* Map special whitespace to '\t', \n', '\r' */
if (ch == '\t') {
    PyUnicode_WRITE(okind, odata, o++, '\');
    PyUnicode_WRITE(okind, odata, o++, 't');
}
else if (ch == '\n') {
    PyUnicode_WRITE(okind, odata, o++, '\');
    PyUnicode_WRITE(okind, odata, o++, 'n');
}
else if (ch == '\r') {
    PyUnicode_WRITE(okind, odata, o++, '\');
    PyUnicode_WRITE(okind, odata, o++, 'r');
}

用于单字符转义,然后在下面进行额外检查更长的转义。对于 Python 2,similar but shorter PyString_Repr() function 做同样的事情。

如果它尝试使用 [=10=],那么当数字紧随其后时,它必须进行特殊处理,以防止它们被解释为八进制文字。始终使用 \x00 更简单且始终正确。