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

Python 增强提案

PEP 278 – 通用换行符支持

作者:
Jack Jansen <jack at cwi.nl>
状态:
最终版
类型:
标准跟踪
创建日期:
2002年1月14日
Python 版本:
2.3
发布历史:


目录

摘要

本PEP讨论了Python如何支持对换行符格式不是平台原生格式的文件进行I/O,以便Python在每个平台上都能读取和导入带有CR (Macintosh)、LF (Unix) 或 CR LF (Windows) 行结束符的文件。

遇到行结束符与当前平台标准不符的文件越来越常见:通过网络下载的文件、不同平台上的远程挂载文件系统、Mac OS X 具有Mac和Unix两种行结束符的双重标准等。

许多工具(如编辑器和编译器)已经能够优雅地处理这种情况,如果Python也能做到这一点将是很好的。

规范

通用换行符支持默认启用,但可以在Python配置期间禁用。

在支持通用换行符的Python中,此功能会自动为所有import语句和execfile()调用启用。对eval()或exec没有特殊支持。

在支持通用换行符的Python中,open()的模式参数也可以是“U”,表示“以通用换行符解释作为文本文件输入打开”。为了与“rb”对称,也允许模式“rU”。模式“U”不能与“+”等其他模式标志结合使用。输入文件中的任何行结束符都将在Python中被视为'\n',因此几乎不需要更改其他代码来处理通用换行符。

换行符的转换发生在所有读取数据的调用中:read()readline()readlines()等。

对于以不同换行约定输出到文件没有特殊支持,因此模式“wU”也是非法的。

以通用换行模式打开的文件对象会获得一个新属性“newlines”,它反映了文件中使用的换行约定。此属性的值是None(尚未读取任何换行符)、"\r""\n""\r\n",或者一个包含所有已见换行符类型的元组。

基本原理

通用换行符支持是在C语言中实现的,而不是在Python中。这样做是因为我们希望带有非原生换行符约定的文件是可导入的,以便Python Lib目录可以通过远程文件系统连接共享,或者在Mac OS X上在MacPython和Unix-Python之间共享。为了实现这一点,通用换行符约定需要对性能产生合理小的影响,这意味着Python实现不是一个选项,因为它会拖慢所有导入。而且由于Visual C++和其他Windows工具会高兴地生成带有多个换行符约定的文件,所以快速检查文件中使用的换行符(如果看到平台本地换行符则将导入交给C代码处理)是行不通的。最后,C语言实现还允许轻松处理回溯等(这些操作会打开Python源模块)。

没有用于以不同换行符约定输出到文件的特殊支持,Python程序被期望自行处理或以平台本地约定写入文件。原因在于输入是困难的情况,在Python中将不同的换行符输出到文件已经足够容易了。

此外,令人惊讶的是,输出实现比输入实现要困难得多:许多输出是通过PyXXX_Print()方法完成的,此时文件对象不再可用,只有FILE *。因此,输出实现需要以某种方式从FILE*到文件对象,因为文件对象是存储当前换行符分隔符的地方。

输入实现没有这样的问题:Python源代码树中没有文件部分从C读取,部分从Python读取的情况,并且在扩展模块中这种情况预计也很少见。如果存在这种情况,唯一的问题是文件对象的newlines属性在直接从C进行的fread()fgets()调用期间不会更新。

部分输出实现,即传递给fp.write()的字符串将被转换为使用fp.newlines作为其行结束符,而所有其他输出则不会,在我看来,这太令人惊讶了。

因为没有通用换行符的输出支持,所以也没有模式“rU+”的支持:前一段的意外因素将以更强的程度存在。

在传递给eval()exec的字符串中不支持通用换行符。设想此类字符串始终具有标准的\n换行符,如果字符串来自文件,则该文件可以用通用换行符读取。

我认为Unicode没有特殊问题。UTF-16不应该带来任何新问题,因为这类文件无论如何都需要以二进制模式打开。与UTF-8的交互也很好:值0x0a和0x0d不能作为多字节序列的一部分出现。

通用换行符文件应该与迭代器和xreadlines()完美配合,因为这些最终都会调用普通文件的readline/readlines方法。

虽然通用换行符对于导入是自动启用的,但对于打开文件却不是,你需要明确声明open(..., "U")。这仍有待商榷,但以下是这种设计的一些原因:

  • 兼容性。那些已经对文本文件中的\r\n进行自行解释的程序将会中断。这类程序的例子包括编辑器,它们在打开带有不同换行符约定的文件时会发出警告。如果通用换行符成为默认设置,这样的编辑器在保存时将悄悄地将你的行结束符转换为本地约定。在Unix上将二进制文件作为文本文件打开的程序也会中断(但可以说它们活该:-)。
  • 接口清晰。通用换行符只支持输入文件,不支持输入/输出文件,因为语义会变得模糊。如果到目前为止所有读取都遇到了Mac换行符,你会写入Mac换行符吗?但是如果你之后又读取了Unix换行符怎么办?

包含newlines属性是为了让真正关心换行符约定的程序(例如文本编辑器)能够检查文件中的内容。然后它们可以以相同的换行符约定保存文件(的副本)(或者,如果文件包含混合换行符,则询问用户如何处理,或以平台约定输出)。

针对参考实现中的一个事项明确征求反馈:通用换行例程是否应该获取全局解释器锁。目前它们没有获取,但这可能被认为是危险的,因为它们可能会修改FileObject中的字段。但是由于这些例程也替代了fgets()fread(),因此很难决定在调用例程时是否持有锁。此外,唯一的危险是,如果两个线程同时读取同一个FileObject,可能会看到一个多余的换行符,或者newlines属性可能会意外地设置为混合。我认为,如果你在两个线程中同时读取同一个FileObject,你无论如何都是在自找麻烦。

请注意,在fgets()fread()替换例程中没有操纵全局可访问指针,只是一些整数值标志,因此核心转储的可能性为零(他说的:-)。

通用换行符支持可以在配置期间禁用,因为它确实会带来微小的性能开销,而且实现尚未在所有可想象的平台上进行测试。在某些平台(例如WinCE或Palm设备)上也可能很愚蠢。如果通用换行符支持未启用,则文件对象不具有newlines属性,因此可以通过一个简单的测试来判断当前的Python是否具有此功能。

if hasattr(open, 'newlines'):
   print 'We have universal newline support'

请注意,此测试使用open()函数而不是file类型,这样就不会在某些Python版本中失败,因为这些版本中file类型不可用(file类型与通用换行符功能在同一版本中添加到内置命名空间)。

此外,请注意,此测试在Python版本 >= 2.5 时再次失败,因为此时 open() 再次成为函数,并且不再与 file type 同义。

参考实现

参考实现可在SourceForge补丁#476814中找到:https://bugs.python.org/issue476814

参考资料

无。


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

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