Python' ascii'编码print语句中的问题

时间:2014-12-12 16:39:38

标签: python linux unicode

系统:Linux上的python 3.4.2。

我正在研究django应用程序(无关紧要),我遇到了它抛出的问题

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

调用 print 时(!)。经过相当多的挖掘,我发现我应该检查

>>> sys.getdefaultencoding()
'utf-8'

但是就像预期的那样,utf8。我还注意到os.path.exists在与unicode字符串一起使用时会抛出相同的异常。所以我检查了

>>> sys.getfilesystemencoding()
'ascii'

当我使用LANG=en_US.UTF-8时,问题就消失了。我现在明白为什么os.path.exists有问题。但我完全不知道为什么print语句受 filesystem 设置的影响。我错过了第三种情况吗?或者只是假设LANG环境值得信任?

另外......我在这里得不到推理。 LANG不会告诉文件名支持哪种编码。它与此无关。它是针对当前环境单独设置的,而不是针对文件系统设置的。为什么python使用此设置来处理文件系统文件名?它使应用程序非常脆弱,因为在未设置LANG或设置为C的环境中运行时,所有文件操作都会中断(并非罕见,尤其是当web应用程序以root身份运行或专门为守护进程创建的新用户。

测试代码(避免终端编码陷阱所需的实际unicode输入):

x=b'\xc4\x8c\xc5\xbd'
y=x.decode('utf-8')
print(y)

问题:

  • 是否有一种良好且可接受的方式使应用程序对LANG设置具有健壮性?
  • 是否有任何现实的理由从环境而不是文件系统驱动程序中猜测文件系统功能?
  • 为什么print会受到影响?

1 个答案:

答案 0 :(得分:1)

LANG用于确定您的区域设置;如果您未设置特定LC_变量,则LANG变量将用作默认值。

文件系统编码由LC_CTYPE variable确定,但如果您没有专门设置该变量,则使用LANG环境变量。

打印使用sys.stdout,这是一个配置了终端使用的编解码器的文本文件。您的终端设置也是特定于区域设置的;您的LANG变量应该真正反映终端设置的区域设置。如果是UTF-8,您需要确保LANG变量反映出来。 sys.stdout使用locale.getpreferredencoding(False)(与未使用显式编码集打开的所有文本流一样)和使用LC_CTYPE的POSIX系统。