Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 263 – 定义 Python 源代码编码

作者:
Marc-André Lemburg <mal at lemburg.com>, Martin von Löwis <martin at v.loewis.de>
状态:
最终版
类型:
标准跟踪
创建日期:
2001 年 6 月 6 日
Python 版本:
2.3
发布历史:


目录

摘要

本 PEP 提议引入一种语法来声明 Python 源文件的编码。编码信息随后将由 Python 解析器用于使用给定编码解释文件。最值得注意的是,这增强了源代码中 Unicode 字面量的解释,并使得可以使用例如 UTF-8 直接在支持 Unicode 的编辑器中编写 Unicode 字面量成为可能。

问题

在 Python 2.1 中,Unicode 字面量只能使用基于 Latin-1 的编码“unicode-escape”编写。这使得编程环境对生活和工作在非 Latin-1 地区(例如许多亚洲国家)的 Python 用户来说相当不友好。程序员可以使用他们喜欢的编码编写 8 位字符串,但对于 Unicode 字面量,则受“unicode-escape”编码的约束。

提议的解决方案

我提议通过在文件顶部使用一个特殊的注释来声明编码,从而使 Python 源代码编码在每个源文件的基础上既可见又可更改。

为了使 Python 了解此编码声明,在处理 Python 源代码数据方面需要进行一些概念上的更改。

定义编码

如果没有给出其他编码提示,Python 将默认使用 ASCII 作为标准编码。

要定义源代码编码,必须将一个魔术注释放置在源文件中的第一行或第二行,例如

# coding=<encoding name>

或(使用流行编辑器识别的格式)

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

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

更准确地说,第一行或第二行必须匹配以下正则表达式

^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)

此表达式的第一个组随后被解释为编码名称。如果 Python 不识别该编码,则在编译期间会引发错误。包含编码声明的行上不得有任何 Python 语句。如果第一行匹配,则忽略第二行。

为了帮助像 Windows 这样的平台(它在 Unicode 文件开头添加 Unicode BOM 标记),UTF-8 签名 \xef\xbb\xbf 也将被解释为“utf-8”编码(即使没有给出魔术编码注释)。

如果源文件同时使用 UTF-8 BOM 标记签名和魔术编码注释,则注释唯一允许的编码是“utf-8”。任何其他编码都将导致错误。

示例

以下是一些示例,以阐明在 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. 不起作用的编码注释
    1. 缺少“coding:”前缀
      #!/usr/local/bin/python
      # latin-1
      import os, sys
      ...
      
    2. 编码注释不在第 1 行或第 2 行
      #!/usr/local/bin/python
      #
      # -*- coding: latin-1 -*-
      import os, sys
      ...
      
    3. 不支持的编码
      #!/usr/local/bin/python
      # -*- coding: utf-42 -*-
      import os, sys
      ...
      

概念

本 PEP 基于以下概念,这些概念必须实现才能使用此类魔术注释

  1. 完整的 Python 源文件应使用单一编码。不允许嵌入不同编码的数据,否则将在编译 Python 源代码期间导致解码错误。

    任何允许以上述方式处理前两行的编码都允许作为源代码编码,这包括 ASCII 兼容编码以及某些多字节编码(例如 Shift_JIS)。它不包括对所有字符都使用两个或更多字节的编码,例如 UTF-16。这样做的原因是使分词器中的编码检测算法保持简单。

  2. 转义序列的处理应继续像现在一样工作,但要支持所有可能的源代码编码,即标准字符串字面量(8 位和 Unicode)都受转义序列扩展的影响,而原始字符串字面量只扩展非常小的转义序列子集。
  3. Python 的分词器/编译器组合需要更新,以按如下方式工作
    1. 读取文件
    2. 假设固定的文件编码,将其解码为 Unicode
    3. 将其转换为 UTF-8 字节字符串
    4. 对 UTF-8 内容进行分词
    5. 编译它,从给定的 Unicode 数据创建 Unicode 对象,并通过首先将 UTF-8 数据重新编码为使用给定文件编码的 8 位字符串数据,从而从 Unicode 字面量数据创建字符串对象

请注意,Python 标识符仅限于编码的 ASCII 子集,因此在步骤 4 之后无需进一步转换。

实施

为了向后兼容目前在字符串字面量中使用非 ASCII 但未声明编码的现有代码,该实现将分两个阶段引入

  1. 允许在字符串字面量和注释中使用非 ASCII,通过内部将缺失的编码声明视为“iso-8859-1”的声明。这将导致任意字节字符串在处理的第 2 步和第 5 步之间正确往返,并为包含非 ASCII 字节的 Unicode 字面量提供与 Python 2.2 的兼容性。

    如果输入中发现非 ASCII 字节,则每个编码不正确的输入文件会发一次警告。

  2. 移除警告,并将默认编码更改为“ascii”。

内置的 compile() API 将增强以接受 Unicode 作为输入。8 位字符串输入遵循上述编码检测的标准程序。

如果将带有编码声明的 Unicode 字符串传递给 compile(),则会引发 SyntaxError

SUZUKI Hisao 正在开发一个补丁;有关详细信息,请参阅 [2]。一个仅实现第一阶段的补丁可在 [1] 获得。

阶段

上述步骤 1 和 2 的实现已在 2.3 中完成,除了将默认编码更改为“ascii”。

默认编码在 2.5 版本中设置为“ascii”。

范围

本 PEP 旨在提供一个从当前(或多或少)未定义的源代码编码情况升级到更健壮和可移植的定义的路径。

参考资料

历史

  • 1.10 及以上版本:请参阅 CVS 历史记录
  • 1.8:在编码正则表达式中添加了“.”。
  • 1.7:在阶段 1 实现中添加了警告。将 Latin-1 默认编码替换为解释器的默认编码。对 compile() 添加了调整。
  • 1.4 - 1.6:细微调整
  • 1.3:采纳了 Martin v. Loewis 的评论:UTF-8 BOM 标记检测、Emacs 风格的魔术注释、实现的两阶段方法

来源:https://github.com/python/peps/blob/main/peps/pep-0263.rst

最后修改:2025-02-01 08:55:40 GMT