Fatal Python error: Py_Initialize: can't initialize sys standard streams LookupError: unknown encoding: cp65001
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
LookupError: unknown encoding: cp65001
搜了一下才发现,Python 3.2 目前并不支持 Windows 上面的 cp65001。话说 65001 代码页不就是 UTF-8 嘛(囧囧囧囧囧)
与其说是不支持,不如说是 bug 更合适些。因为执行之后 Windows 就跳出一个警告框说“ python.exe 已经停止响应”了……
于是,试着改变代码页到 GBK:
chcp.com 936
结果却是:
Invalid code page
Windows 声称这是一个无效的代码页。为什么? 编码是什么
好了,暂且忘记 cmd.exe 诸如此类令人不愉快的东西,在 IDLE 上试一试。
我不知道有多少 Linux 程序员写 Python 的时候会用到 IDLE。对于这些习惯了终端+文本编辑器的用户来说,IDLE 看起来是个无关紧要的附属品,也许它的定位只是用来帮助初学者入门的一个开发环境?
不过,容易被人们忽略的一点是:IDLE 本身是个跨平台的环境,这意味着它可以无条件支持 Unicode(只要系统上有相应的字体),用它来解释执行程序不必受制于特定终端环境的拘束。这一点在 Windows 上很重要,因为 cmd.exe 这玩意实在是太差劲了,所以估计很多人在 Windows 下交互执行 Python 的时候还是会选择 IDLE 的。
进入 IDLE。我们可能要关心一下这个 Windows 系统下面的默认编码方式是什么,Python 3 里面有两个函数:
>>> print(bytes ('你好,世界', 'utf-8') .decode ('cp437'))
你好,世界
Python 直接把 UTF-8 编码的字符串输出到了 cp437 代码页的终端,相当于强制用 cp437 来解码 UTF-8 文本,产生了无意义的乱码。
用文本编辑器写一个内容是“你好,世界”的文件,以 UTF-8 编码保存。在 cmd.exe下通过 type 显示,结果和上面是相同的。 cmd.exe 和 PowerShell ISE 的微妙之处对比
在当前区域设置(英语/美国)下,两者执行 chcp.com 显示的当前活动代码页都是 437。
只有 cmd 下 Python 的 sys.stdout.encoding 默认是 cp437(与活动代码页相同);PowerShell ISE 下 sys.stdout.encoding 则是 cp1252(ANSI)。
locale.getpreferredencoding 永远是系统本身默认的 cp1252,这是一个系统全局值。
cmd 无法输入中文,不能正确显示文件系统中的中文文件名;PowerShell ISE 能够输入中文,能显示中文文件名。
在缺少 936 代码页的情况下,两者都不能够通过执行脚本或 type 文件内容正确显示中文字符(无论是 GBK 还是 UTF-8),会产生乱码。 为什么 Windows 会缺少 GBK 代码页?
回到最初的那个问题上来,为什么执行 chcp.com 936 不能切换到 GBK 代码页?为什么 cmd.exe 和 PowerShell 里不能正常显示中文?
这个问题让我百思不得其解。花了几个小时找到了原因,简而言之:因为 Windows 的“区域和语言”设置不对。
“Language for non-Unicode programs”这个选项不是简体中文,所以就不能用 GBK,手动 chcp.com 也会告诉你该代码页无效。所以必须要在控制面板里设置成简体中文,重启后才能生效。
好吧,问题来了,为什么这里只能单选?如果我既想使用 936(GBK)编码的应用程序,又想使用 932(日语)编码的应用程序,难道每次都要在这里改完后再重启吗?为什么他们不能给一个详细的代码页列表让用户多选、需要时可以动态加载?
Windows 设计的龌龊之处就在这里。如果你不去设置 system locale 为中文并重启,所有 non-Unicode 程序里的中文字符集都是不会出现的,只能显示成一个方框,比如cmd.exe 里:
还有 Vim 里( set fileencodings=utf-8,gbk ),GBK 编码的文本和 UTF-8 编码的文本都一样无法显示。(按理说 Vim 应该不能算 non-Unicode 程序吧……谁知道呢?!)
改过"Language for non-Unicode programs”为中文并且重启系统之后,Vim 立即显示正常:
再进 cmd.exe ,默认活动代码页 936。这段 Python 程序终于也能正确输出了:
也许 Windows 这种蛋疼的设计是因为考虑到英文用户一般不会需要多余的 Unicode 和代码页字符集,这么做可以节省系统启动时间?谁知道呢,Windows 用户不是最喜欢拿所谓的“启动时间快”作为衡量系统性能的指标了吗……
切换到 cp65001(UTF-8 Unicode), PYTHONIOENCODING 设置成 utf-8,按理来说这种方式不应该出问题,但是这输出怎么看都不像是正常(如下图所示)。不想深究到底为什么了,总之 Windows 下面东西的复杂程度以我这种智商是永远都不能够理解的…… Python 除了标准输入输出,还有…… 文件名
open ('文件名测试', 'w')
Python 中对文件系统的操作基本上是不受默认编码影响的,只要sys.getfilesystemencoding () 的结果是 utf-8(现代 Linux)或者 mbcs(现代 Windows NT 系统上)。两者本质上都是 Unicode 编码。 文件输入输出
文件读写不属于标准I/O,因此和环境变量 PYTHONIOENCODING 无关。
for c in ['utf-8', 'gbk']:
with open ('test_%s.txt' % c, 'w', encoding=c) as output:
try:
output.write ('你好,世界\n')
except Exception as err:
print('\nWriting to file using %s:\n' % c, str (err))
由于在 open ()中显式指定了中文编码方式(encoding='utf-8'或encoding='gbk'),输出“你好,世界”这样的中文文本在任何平台上都应该能够得到正确的结果。
然而对于:
with open ('test_default.txt', 'w') as output:
try:
output.write ('你好,世界\n')
except Exception as err:
print('\nWriting to file using default encoding:\n', str (err))
由于没有指定编码方式,Python 会自动使用系统默认的编码方式来进行输出。如果系统默认编码是 cp437 或 cp1252,由于中文字符在这些代码页中显然不存在对应值,Python 会抛出一个熟悉的错误:
File "c:\Python32\lib\encodings\cp437.py", line 19, in encode
return codecs.charmap_encode (input,self.errors,encoding_map)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-1: character maps to <undefined>
当然,当系统默认编码为 cp936(GBK)时,无论
output.write ('你好,世界')
还是
print ('你好,世界')
都可以正常工作。因为“你好,世界”这个 Unicode 字符串是可以被完全转换成 GBK 中的对应编码的。 一些总结和思考
虽然 Python 3 使用 Unicode 编码的字符串,但是在跨平台的程序中依然要取得系统的默认编码用于后续处理,因为并不是所有的终端环境都支持全部的 Unicode 字符集: