pab*_*obm 6 python encoding exception python-2.x
以下代码检查了float()在输入非ascii符号时方法的行为:
import sys
try:
float(u'\xbd')
except ValueError as e:
print sys.getdefaultencoding() # in my system, this is 'ascii'
print e[0].decode('latin-1') # u'invalid literal for float(): ' followed by the 1/2 (one half) character
print unicode(e[0]) # raises "UnicodeDecodeError: 'ascii' codec can't decode byte 0xbd in position 29: ordinal not in range(128)"
Run Code Online (Sandbox Code Playgroud)
我的问题:为什么错误信息e[0]以Latin-1编码?默认编码是Ascii,这似乎是unicode()预期的.
平台是Ubuntu 9.04,Python 2.6.2
e [0]不用latin-1编码; 事实上,当解码为latin-1时,字节\ xbd是字符U + 00BD.
转换发生在Objects/floatobject.c.
首先,必须将unicode字符串转换为字节字符串.使用PyUnicode_EncodeDecimal()以下方式执行:
if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
PyUnicode_GET_SIZE(v),
s_buffer,
NULL))
return NULL;
Run Code Online (Sandbox Code Playgroud)
这是实现的unicodeobject.c.它不执行任何类型的字符集转换,它只是写入值等于字符串的unicode序数的字节.在这种情况下,U + 00BD - > 0xBD.
格式化错误的语句是:
PyOS_snprintf(buffer, sizeof(buffer),
"invalid literal for float(): %.200s", s);
Run Code Online (Sandbox Code Playgroud)
其中s包含先前创建的字节字符串.PyOS_snprintf()写一个字节字符串,并且s是一个字节字符串,所以它只是直接包含它.
非常好的问题!
我冒昧地深入研究Python的源代码,这仅仅是正确设置linux发行版的命令(apt-get source python2.5)
该死的,约翰米利金打败了我.这是正确的,这PyUnicode_EncodeDecimal是它在这里做到的答案:
/* (Loop ch in the unicode string) */
if (Py_UNICODE_ISSPACE(ch)) {
*output++ = ' ';
++p;
continue;
}
decimal = Py_UNICODE_TODECIMAL(ch);
if (decimal >= 0) {
*output++ = '0' + decimal;
++p;
continue;
}
if (0 < ch && ch < 256) {
*output++ = (char)ch;
++p;
continue;
}
/* All other characters are considered unencodable */
collstart = p;
collend = p+1;
while (collend < end) {
if ((0 < *collend && *collend < 256) ||
!Py_UNICODE_ISSPACE(*collend) ||
Py_UNICODE_TODECIMAL(*collend))
break;
}
Run Code Online (Sandbox Code Playgroud)
看,根据Unicode的向后兼容性,它保留了所有unicode代码点<256,即latin-1字符.
附录
有了这个,您可以通过尝试其他非latin-1字符进行验证,它将抛出一个不同的异常:
>>> float(u"?")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'decimal' codec can't encode character u'\u0127' in position 0: invalid decimal Unicode string
Run Code Online (Sandbox Code Playgroud)