文号
829621
阅读
11588
回复
4
收藏
1
Python 3.6对于Windows平台下现代字符串的优化
2017/01/19
IP:内蒙古

一、控制台(PEP 528)

Python 2.x/3.x在Windows平台,长期以来对于控制台输入输出的做法,都是转换为OEM编码按字节输入输出。但是事实上OEM编码已经过时,在输出某些文本的时候,经常会出现一些OEM编码不支持的字符,导致print直接崩溃,让人感到非常棘手。

Python迟迟未改变可能是因为:长期以来(直到Windows 8.1)Windows控制台都在使用OEM点阵字体,根本无法显示Unicode字符,所以大多数情况下是不可能发现控制台居然还能显示Unicode字符的。直到Windows 10,控制台才开始使用可以显示Unicode字符的TrueType字体。

根据最新的Python 3.6.0发行说明(XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX),Python 3.6加入了以下特性:

在交互模式下,sys.stdin/stdout/stderr将使用UTF-8编码,.encoding返回'utf-8',而在重定向模式下,将继续使用以前默认的ANSI编码,.encoding返回'cpXXX'。(顺便说一下,重定向模式下Python 2.7这里居然返回空白,需要locale.getpreferredencoding()。。。)

可使用%PYTHONLEGACYWINDOWSSTDIO%环境变量以阻止交互模式下使用UTF-8,改为使用以前的OEM编码,.encoding将返回'cpXXX',代码页可能和ANSI编码不同。

虽然重定向模式下使用的仍然是ANSI编码,但是可以设置环境变量%PYTHONIOENCODING%为utf-8强制输出为UTF-8,实际上也不是问题,只是为兼容性做的让步而已。

也就是说,现在已经不用担心Python 3在print的时候会莫名其妙崩溃了。

二、文件名(PEP 529)

除了控制台以外,对于以字节字符串表示的文件名,也将以UTF-8处理,sys.getfilesystemencoding()将返回'utf-8'。

可以使用%PYTHONLEGACYWINDOWSFSENCODING%环境变量和sys._enablelegacywindowsfsencoding()改回原来的MBCS方式,sys.getfilesystemencoding()将返回原来的'mbcs'。

不过其实这个改变影响并不大,Python早就可以在Windows下使用Unicode文件名了。

[ 修改于9年11个月前 - 2017/01/20 01:05:59 ]
acmilan作者
9年11个月前修改于 9年11个月前IP:浙江
829622
1楼
Python 3.6可以下载zip版本用于再分发,不过由于它是用VC++2015编译的,在Windows 7等老系统运行会报缺少Universal CRT DLLs。这些DLL可以在Windows 10 SDK里面找到。

这里上传一份目前的最新版本(10.0.14393.33),与Python解压到相同目录即可使用。


attachment icon UCRTBASE_DLL_14393_33_x86_x64.rar 1.52MB RAR 24次下载
引用
评论
acmilan作者
9年11个月前修改于 9年10个月前IP:内蒙古
829633
2楼

如果必须用老版本的话,有一个解决方法,在IDLE中运行脚本就可以避免出现print崩溃。原因是IDLE是支持Unicode的。

引用
评论
acmilan作者
9年11个月前修改于 9年10个月前IP:内蒙古
829634
3楼
其实OEM代码页主要是给DOS程序使用的,除了微软自己以外没人用OEM代码页,都是用的ANSI代码页。用OEM代码页只能保证显示正确,但是却带来了更多的麻烦和问题。
引用
评论
acmilan作者
9年10个月前修改于 9年10个月前IP:浙江
829756
4楼

Python 2.7使用from __future__ import division,absolute_import,print_function,unicode_literals,可以在语法层面开启Python 3模式。

Python 2/3在细节上的区别更多,比如模块、类、函数名称,基类object之类的,真正移植起来要处理的东西很多,远不止四个import这么简单,但是以后想要移植到或者兼容Python 3.x就会方便很多,因为这四个功能是Python 2和Python 3移植困难的最主要原因。

如果要加中文的话,还要加上# -*- encoding: utf-8 -*-,因为Python 2.7默认认为脚本是ISO-8859-1。

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from __future__ import division,absolute_import,print_function,unicode_literals

import sys;
import os;

print("Python版本:" + str(sys.version_info.major));

特别是如果需要跨平台的话,即使是想要继续使用Python 2,也建议加上encoding声明和unicode_literals,不然就只能用英文了。

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from __future__ import unicode_literals
引用
评论
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的