[译]如何定义python源文件的文件编码

简介

这篇文章是为了介绍定义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

时间: 2024-12-09 01:37:07

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

python读取中文文件编码问题

python 读取中文文件后,作为参数使用,经常会遇到乱码或者报错asii错误等. 我们需要对中文进行decode('gbk') 如我有一个data.txt文件有如下内容: 百度 谷歌 现在想读取文件中内容构建查询语句代码如下: f=open('data.txt','r') for i in f.readlines(): data_line=i.strip() data=data_line.decode("gbk") print "this is %s"%data

IntelliTest(3) - Test to Code Binding, Test Case Management[译]

[作者提醒:从Visual Studio 2015 RC 版本开始,"Smart Unit Tests"已经更名为"IntelliTest"] ??在这篇文章中,我们讲到IntelliTest如何自动生成测试用例,以及当被测代码改变时,如何更新这些用例.针对一段被测代码,IntelliTest会生成一个PUT方法,和一个或多个测试用例方法.在下面的示例图中,展示了以Pex开头的特性的使用,它用于定义用例和被测代码的约束关系,这些特性都定义在Microsoft.Pex

IntelliTest(4) – Hands on[译]

??在我们写传统单元测试时,为了达到一定的覆盖率,开发者需要反复的做一些类似的工作,比如,写测试用例,查看哪些代码未被覆盖,继续写测试用例覆盖之,直到所有的代码都被覆盖. ??有了IntelliTest后,这一切都变得不一样了.我们会手把手的介绍IntelliTest技术,为了便于大家理解,会使用一个demo项目. 一.准备demo项目 ??按照上面给出的GitHub地址,克隆项目后,打开PokerLeagueManager.sln.这个demo主要用于跟踪统计每周的扑克牌联赛数据,每个玩家的游

IntelliTest(1) - One Test to rule them all[译]

??在传统单元测试方案中,每个测试用例代表一个使用场景,开发者可以使用断言来验证每种场景下的输入和输出是否符合预期. ??针对相对少量的测试用例来说,此方案似乎已足够,但是,那些做了多年开发的老鸟们深知,即使经过相对较全面测试的代码,依然潜伏着bug,就像一个常规的输入可以得到正确的结果,但是换一个类似的但是未经测试的输入,它就神奇的崩了. 传统单元测试的生成 ??IntelliTest可以生成传统单元测试用例.当在一段被测试代码上运行IntelliTest时,它会尽量去生成高覆盖率的单元测试用

IntelliTest(5) - The IntelliTest Reference Manual[译]

??有一套非常棒的工具集将大大提高我们的工作效率,选择一个正确的工具和让这个工具做它擅长的事情也是非常重要的.工具集越大,就越容易找到适合你当前工作的工具. ??不管使用任何工具,为了让它发挥更大的性能,了解它的功能,它的短板,以及它最擅长的事情都是相当重要的.IntelliTest就是一个功能强大,但相对复杂的工具,要说明这一点很容易,回答如下三个问题: 它可以帮助我们做什么? 它的短板在哪里? 作为开发者,我们怎样可以最大化的利用它功能? 要回答这些问题,可以通过查看博客,浏览介绍文档,或者

IntelliTest(0) - Introducing Smart Unit Tests[译]

[作者提醒:从Visual Studio 2015 RC 版本开始,"Smart Unit Tests"已经更名为"IntelliTest"] ??关于IntelliTest,有一个短视频,如果你还没看过,强烈建议去看一下.其中介绍了IntelliTest给测试开发带来的新特性,这些新特性将帮助开发者克服在初写单元测试时的惰性.除了视频中所描述的那部分,IntelliTest还包括许多其他特性,这一系列的博客将完善你对整个IntelliTest的知识. ??首先,我

IntelliTest(2) - A mental model[译]

[作者提醒:从Visual Studio 2015 RC 版本开始,"Smart Unit Tests"已经更名为"IntelliTest"] ??在这篇文章中,我们介绍了IntelliTest,如果你还没有阅读过,强烈建议先阅读它. ??我们接着讨论IntelliTest的相关内容.IntelliTest是怎么自动生成高覆盖率的测试用例的?它运行的原理是什么?如果可以将其运行原理抽象成模型,对我们理解并使用它都大有帮助. 运行时的检测和监控是IntelliTest

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

转载于:http://ask.dcloud.net.cn/article/152 iOS有两种证书和描述文件: 证书类型 使用场景 开发(Development)证书和描述文件 用于开发测试,在HBuilder中打包后可在真机环境通过Safari调试 发布(Distribution)证书和描述文件 用于提交Appstore,在HBuilder中打包后可使用Application Loader提交到Appstore审核发布 准备环境 必需要有苹果开发者账号,并且加入了“iOS Developer

[翻译]The Neophyte&#39;s Guide to Scala Part 12: Type Classes

The Neophyte's Guide to Scala Part 12: Type Classes 过去的两周我们讨论了一些使我们保持DRY和灵活性的函数式编程技术,特别是函数组合,partial function的应用,以及currying.接下来,我将会继续讨论如何使你的代码尽可能的灵活. 但是,这次我们将不会讨论怎么使用函数作为一等对象来达到这个目的,而是使用类型系统,这次它不是阻碍着我们,而是使得我们的代码更灵活:你将会学到关于 type classes 的知识. 你可能会觉得这是一