简介

这篇文章是为了介绍定义python源文件文件编码的方法。python解释器可以根据所指定的编码信息对当前文件进行解析。通常来说,这种方法可以提高解析器对Unicode编码的源文件的识别,并且支持书写Unicode编码,例如在一个支持unicode编码的编辑器中使用UTF-8。

问题

在python2.1中,unicode编码只能通过Latin-1中的“unicode-escape”的方式来实现。这让很多平时不使用Latin-1编码的用户感到非常的不友好,尤其是大多数的亚洲国家更是这样。程序员可以使用他们所习惯的编码来编写8-bit的字符代码,却不得不因为要用到unicode编码而使用"unicode-escape"。

解决方法

我们希望让每一个python文件都可以通过在文件顶端书写一些特定的注释的方法,来实现python源代码编码的可见性和易维护性。

为了让python能够识别出文件编码的定义,需要做一些列关于对python源文件代码数据的扩充。

定义编码

在没有指定其它编码的情况下,python默认使用ASCII作为标准编码。

如果想要定义文件代码编码,一个特殊的注释应该放到源文件的第一或第二行,例如:

          # coding=<encoding name>

或(使用一种大多数编辑器都能够识别的方式)

          #!/usr/bin/python
# -*- coding: <encoding name> -*-

          #!/usr/bin/python
# vim: set fileencoding=<encoding name> :

恰好,第一或第二行都完全符合正则表达式“coding[:=]\s*([-\w.]+)”。这个表达式获取到的第一组信息就是编码名称。如果python无法识别编码名称,那么将会在编译完成时报错。在python编码定义的行中,严禁出现python的其它声明。

为了避免一些系统,例如windows,在unicode文件头中增加了文件头标记,UTF-8的签名“\xef\xbb\xbf”同样会作识别文件编码的参照(即使没有设置文件编码注释)。

如果一个源文件既有UTF-8文件头标记,又用注释声明了文件编码,那么此时仅可以声明成“UTF-8”。其它的编码将会导致错误。

示例

以下示例用语说明使用不同的方法,如何在python文件顶端定义python源文件编码。

文件:

1. 利用解释器,并使用Emacs风格的文件编码

注释:

          #!/usr/bin/python
# -*- coding: latin-1 -*-
import os, sys
... #!/usr/bin/python
# -*- coding: iso-8859-15 -*-
import os, sys
... #!/usr/bin/python
# -*- coding: ascii -*-
import os, sys
...

2. 不使用解释器,使用一段文字描述

          # This Python file uses the following encoding: utf-8
import os, sys
...

3. 文本编辑器中,可以有不同的方式来定义文件的编码,例如:

          #!/usr/local/bin/python
# coding: latin-1
import os, sys
...

4. 不使用编码注释,python解释器会将文件当成是ASCII:

          #!/usr/local/bin/python
import os, sys
...

5. 不会生效的编码注释:

遗失了“coding:”前缀:

          #!/usr/local/bin/python
# latin-1
import os, sys
...

编码注释不在第一和第二行:

          #!/usr/local/bin/python
#
# -*- coding: latin-1 -*-
import os, sys
...

不支持的编码:

          #!/usr/local/bin/python
# -*- coding: utf-42 -*-
import os, sys
...

理念

我们是根据以下理念来实现的编码注释的用法:

1. 一个python源文件应该具有唯一的编码。内部混杂多种编码数据的行为是不被允许的,并且在编译时会报错。

任意一个能够识别出源码前两行,并且符合以上讨论的编码,都可以作为源码文件的编码,包括ASCII兼容编码和某些多字节编码,如Shift_JIS。所有字符都使用至少两个字节的编码无法被识别,例如UTF-16。这是为了让编码检测算法的检测功能更加简洁。

2. 对于未定义的信息,应该什么都不处理而继续进行分析,就像当前的行为一样。其实所有的可用编码值,都是标准的字符串字符(都是8-bit的Unicode),它们对于其它可能出现在代码中的未定义的信息来说只是很小的一部分。

3. python的 tokenizer/compiler 组件应该被更新为一下的工作流程:

a)读取文件

b)将文件解码成Unicode编码,即一个固定的、假设的编码

c)将文件转换为UTF-8字节字符串

d)tokenize UTF-8化的内容

e)编译,根据给定的Unicode数据创建Unicode对象 ,并且根据文件中给定的编码将UTF-8数据重编码成新的8-bit字符串数据。

注意,python的识别码被限制为了ASCII编码集合,所以在步骤d后不用再对它进行额外的转换。

向下兼容

为了兼容已存在的,没有使用ASCII编码并且没有声明编码格式的,现在需要进行2步来进行使用:

1. 将所有不使用ASCII编码并且没有做注释的文件,将它们当作丢失了“iso-8859-1”定义。这会导致强行将字节字符串的处理放置到步骤2-5之前,并且在python2.2中,提升了对非ASCII字符——Unicode的兼容。

当发现输入文件没有ASCII字节时,会在编码输入文件的时候产生一个警告。

2. 删除警告,并将默认编码格式设置为“ASCII”。

内建compile() API,用来提高对输入文件为Unicode编码时的处理能力。字节字符串的输入的处理方式在上文中已经进行过描述。

如果一个带有编码声明的字符串传递给了compile(),那么将会发生一个SyntaxError。

SUZUKI Hisao可以通过使用patch来兼容,查看[2]获取更多信息。

只有在第一步可以使用的patch,在[1]。

新进展

向下兼容中的步骤1和2已经在2.3版本中进行了完善,除了将默认编码置为“ascii”。

在2.5版本中,实现了将默认编码设置成“ascii”。

链接

    [1] Phase 1 implementation:
http://python.org/sf/526840
[2] Phase 2 implementation:
http://python.org/sf/534304

历史

    1.10 and above: see CVS history
1.8: Added '.' to the coding RE.
1.7: Added warnings to phase 1 implementation. Replaced the
Latin-1 default encoding with the interpreter's default
encoding. Added tweaks to compile().
1.4 - 1.6: Minor tweaks
1.3: Worked in comments by Martin v. Loewis:
UTF-8 BOM mark detection, Emacs style magic comment,
two phase approach to the implementation

版权

    This document has been placed in the public domain.

Source: https://hg.python.org/peps/file/tip/pep-0263.txt

[译]如何定义python源文件的文件编码的更多相关文章

  1. [译]一个灵活的 Trello 敏捷工作流

    [译]一个灵活的 Trello 敏捷工作流 翻译自 An Agile Trello Workflow That Keeps Tasks Flexible Getting things done 可不只 ...

  2. python读取中文文件编码问题

    python 读取中文文件后,作为参数使用,经常会遇到乱码或者报错asii错误等. 我们需要对中文进行decode('gbk') 如我有一个data.txt文件有如下内容: 百度 谷歌 现在想读取文件 ...

  3. [译]如何使用 Docker 组件开发 Django 项目?

    原文地址:Django Development With Docker Compose and Machine 以下为译文 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包 ...

  4. [转]iOS证书(.p12)和描述文件(.mobileprovision)申请

    转载于:http://ask.dcloud.net.cn/article/152 iOS有两种证书和描述文件: 证书类型 使用场景 开发(Development)证书和描述文件 用于开发测试,在HBu ...

  5. [caffe]linux下安装caffe(无cuda)以及python接口

    昨天在mac上折腾了一天都没有安装成功,晚上在mac上装了一个ParallelDesktop虚拟机,然后装了linux,十分钟就安装好了,我也是醉了=.= 主要过程稍微记录一下: 1.安装BLAS s ...

  6. [Swift]基础

    [Swift]基础 一, 常用变量 var str = "Hello, playground" //变量 let str1="Hello xmj112288" ...

  7. [Ruby on Rails系列]4、专题:Rails应用的国际化[i18n]

    1. 什么是internationalization(i18n)? 国际化,英文简称i18n,按照维基百科的定义:国际化是指在设计软件,将软件与特定语言及地区脱钩的过程.当软件被移植到不同的语言及地区 ...

  8. Java基础 之软引用、弱引用、虚引用 ·[转载]

    Java基础 之软引用.弱引用.虚引用 ·[转载] 2011-11-24 14:43:41 Java基础 之软引用.弱引用.虚引用 浏览(509)|评论(1)   交流分类:Java|笔记分类: Ja ...

  9. MongoDB入门教程三[数据类型]

    MongoDB的文档使用BSON(Binary JSON)来组织数据,BSON类似于JSON,JSON只是一种简单的表示数据的方式,只包含了6种数据类型(null.布尔.数字.字符串.数组及对象),不 ...

随机推荐

  1. HTTP缓存控制总结

    引言 通过网络获取内容既缓慢,成本又高.大的相应需要在客户端和服务器之间多次往返通信,这拖延了浏览器可以使用和处理内容的时间,同时也增加了通信的成本.因此,缓存和重用以前获取到的资源的能力成为性能优化 ...

  2. ckeditor_3.6.6.2+CKFinder2.0.2配置

    一.首先工具的下载,找到相应的版本进行下载     ckeditor_3.6.6.2+CKFinder2.0.2 http://ckeditor.com/download      打开war文件,然 ...

  3. Cocos2dx 学习笔记整理----开发环境搭建

    最近在学习cocos2dx,预备将学习过程整理成笔记. 需要的工具和环境整理一下: 使用的版本 cocos2dx目前已经出到了v3.1.1,学习和项目的话还是用2.2.3为宜,毕竟不大想做小白鼠,并且 ...

  4. Spring MVC之Action返回类型

    Spring MVC支持的方法返回类型 1)ModelAndView 对象.包含Model和View对象,可以通过它访问@ModelAttribute注解的对象. 2)Model 对象.仅包含数据访问 ...

  5. form表单传递下拉框的Value和Text值,不适用Jquery传递

    同时获取下拉框的Value和Text值的解决办法:添加一个<input type="text" >文本框,用户选中一项后就将该项的value值给他 然后接受页面获取该文 ...

  6. vim中c/c++源码跳转

    在使用vim阅读c/c++代码的时候,代码跳转很重要, 在学习redis代码的时候遇到这个问题. 网上查找之后通过实践发现cscope比较好用,可以很方便的实现跳转 1. 安装cscope sudo ...

  7. 单片机联网,UIP实现tcp/udp协议

    UIP是单片机界联网的一个很好地选择,移植这个库有点复杂,首先是第一步,网卡驱动要写好,使用的网卡芯片为ENC28J60,驱动可以再工程包里面找到 //配置网卡硬件,并设置MAC地址 //返回值:0, ...

  8. width这样读取出来是一个字符串,并且带有单位,但是offsetwidth返回的是一个数值。

    <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <title> ...

  9. Qt编译Oracle OCI驱动

    最近使用qt开发了一个访问数据库的工具, 默认使用ODBC驱动注入的方式,后来发现Oracle中ODBC驱动注入经常失败. 后来就想直接使用OCI方式访问,而默认情况下Qt只有Sqlite和ODBC驱 ...

  10. mvc中上传图片到指定文件夹中

    前台: @using (Html.BeginForm("AddImg", "UpFileImg", FormMethod.Post, new { enctype ...