为什么我在python warnings.formatwarning格式字符串中出现编码错误?

为什么我在python warnings.formatwarning格式字符串中出现编码错误?,python,encoding,warnings,Python,Encoding,Warnings,我在这一行得到编码错误: s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message) UnicodeEncodeError:“ascii”编解码器无法对位置44中的字符u'\xc4'进行编码:序号不在范围内(128) 我试图通过将所有参数组合传递到字符串格式来重现此错误,但最接近的是“ascii解码”错误(通过同时传递unicode和高ascii字符串,这迫使使用ascii解码器将字符串转换为unicode)

我在这一行得到编码错误:

s =  "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
UnicodeEncodeError:“ascii”编解码器无法对位置44中的字符u'\xc4'进行编码:序号不在范围内(128)

我试图通过将所有参数组合传递到字符串格式来重现此错误,但最接近的是“ascii解码”错误(通过同时传递unicode和高ascii字符串,这迫使使用ascii解码器将字符串转换为unicode)


但是,我没有设法得到“ascii编码”错误。有人知道吗?

您正在传递的一个操作数不适合ascii编码-可能它包含Unicode或Latin-1字符。将格式字符串更改为Unicode,看看会发生什么情况。

当Python试图强制参数时,会发生这种情况:

s = u"\u00fc"
print str(s)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc' in position 0: ordinal not in range(128)

这是因为您的一个参数是一个对象(不是任何类型的字符串),Python对其调用
str()
。有两种解决方案:使用unicode字符串作为格式(
s=u”%s…“
),或者使用
repr()

将unicode和str对象混合在一起

说明: 在Python2.x中,有两种对象可以包含文本字符串。str和unicode。str是一个字节字符串,因此它只能包含0到255之间的字符。 Unicode是一个Unicode字符字符串

您可以使用“编码”和“解码”方法在str和unicode之间进行转换:

请注意编码。编码是将unicode文本仅表示为字节字符串的方法

如果您尝试同时添加str和unicode,Python将尝试将两者转换为另一种。但默认情况下,它将使用ASCII作为编码,这意味着a-z、a-z和一些额外字符,如
!“#$%&/()=?'{[]}
等。其他任何操作都将失败

在这一点上,您将得到编码错误或解码错误,这取决于Python是否尝试将unicode转换为str或str转换为unicode。通常它尝试解码,即转换为unicode。但有时它决定不解码,而是强制转换为字符串。我不完全确定原因

更新: 上面出现编码错误而不是解码错误的原因是,上面代码中的
message
既不是str也不是unicode。它是另一个对象,具有str方法。因此Python执行str(message)因为内部存储的消息是无法强制转换为ascii的unicode对象

或者,更简单的回答是:它失败是因为warnings.warn()不接受unicode消息

现在,解决方案:

不要混合使用str和unicode。如果您需要使用unicode,而且显然需要,请确保所有字符串始终是unicode。这是确保避免这种情况的唯一方法。这意味着,无论何时从磁盘读入字符串,或调用可能返回除纯ascii str以外的任何内容的函数,都应尽快将其解码为unicode可能的。 当您需要将其保存到磁盘或通过网络发送,或将其传递给不懂unicode的方法时,请尽可能晚地将其编码到str


在这种特定情况下,问题是您将unicode传递给warnings.warn(),但您不能这样做。请传递字符串。如果您不知道它是什么(这里的情况似乎是这样的)因为它来自其他地方,您使用repr的try/Exception解决方案工作正常,尽管进行编码可能会产生解码错误,即s=“%s%s”%(unichr(2000),chr(200))这里的错误似乎是其他原因。@cortex:有时Python决定不强制使用unicode,而是强制使用字符串。我不确定这个决定是如何做出的。格式在“警告”模块中,所以我不想更改它,而是添加了repr()围绕传递的参数听起来真的很好。谢谢!然后你会得到额外的引号和额外的u。作为一个黑客,但不是很漂亮。当数据库抛出的警告被捕获用于日志记录时会发生错误。由于日志记录失败,我对原始问题一无所知,这是最糟糕的地方。我喜欢我的日志可读性好这是下一个人,所以我决定在try:except:block中包装格式,首先“很好地”完成它,然后使用repr()只有在编码错误的情况下,包括抛出关于编码问题的额外警告。IMHO,这不是黑客行为,更好、更安全,日志记录。我相信在Python 2.x下,只要您知道自己在做什么,日志记录是Unicode安全的(Unicode和Python 2.x通常都是这样,而不仅仅是日志记录)。任何以字节为单位的消息(即str对象而非Unicode)需要使用适当的编码将其转换为Unicode,否则会出现此类问题-由str和Unicode错误混合引起。基于文件的日志处理程序允许您指定编码,而基于流的处理程序可以接受一个周围有编码包装的流。@Ivan Virabyan-
warnings
是act通常与
日志记录不同的模块我想发问者完全知道,问题是unicode和str以某种方式混合在一起;问题是,为什么在一个通常应该强制输出为unicode的操作上会触发此错误。这是可能的,但我想得到一个详尽的答案。问题仍然是unicode和str的混合。为什么它只会得到一个错误在这个特定的例子中,我不知道,我不能复制它。但我自己也看到过。这就是你可以复制它的方式:
导入警告;警告。警告
噢,当调用warnings.warn时,您会得到它……您难道不能这么说吗?不清楚代码不是您的代码,而是在标准库中。您应该说您的问题是什么,而不是您认为是问题的一般问题,因为它通常不是。我已更新了下面的答案,并提供了更多详细信息。
>>> "thisisastring".decode('ascii')
u'thisisastring'

>>> u"This is ä string".encode('utf8')    
'This is \xc3\xa4 string'