PEP 3117 – 后缀类型声明
- 作者:
- Georg Brandl <georg at python.org>
- 状态:
- 已拒绝
- 类型:
- 标准跟踪
- 创建:
- 2007 年 4 月 1 日
- Python 版本:
- 3.0
- 历史记录:
摘要
本 PEP 提出在 Python 中添加后缀类型声明语法。它还指定了一个新的 typedef
语句,用于在类型和声明符之间创建新的映射。
它的接受将极大地增强 Python 用户体验,并消除阻止其他编程语言用户转向 Python 的一个缺点。
基本原理
长期以来,Python 一直缺乏显式类型声明。作为该语言偏离其禅宗的少数几个方面之一,这个缺点引发了 Python 异端分子和 PSU 成员之间的许多讨论(例如,参见 [EX1],[EX2] 或 [EX3]),它也使它不太可能成为大规模的企业成功。
但是,如果想结束这种痛苦,就必须找到一种合适的 Python 语法。在几乎所有拥有类型声明的语言中,类型声明都缺乏这种品质:它们冗长,通常需要多个单词来表示一个类型,或者难以理解(例如,某种语言使用完全无关的 [1] 形容词,如 dim
来进行类型声明)。
因此,本 PEP 将转向类型声明与另一个大胆的举动结合起来,这将再次证明 Python 不仅是面向未来的,而且是拥抱未来的:引入 Unicode 字符作为源代码的组成部分。
Unicode 使得用更少的字符表达更多内容成为可能,这符合 禅宗(“可读性很重要。”)。此外,它消除了对单独的类型声明语句的需求,最后但并非最不重要的是,它使 Python 赶上了 Perl 6,Perl 6 已经使用 Unicode 来表示其运算符。 [2]
规范
当类型声明模式处于活动状态时,语法将发生更改,因此每个 NAME
必须包含两个部分:一个名称和一个类型声明符,它恰好是一个 Unicode 字符。
声明符唯一地指定名称的类型,如果它出现在表达式的左侧,则将强制执行此类型:如果返回的类型与声明的类型不匹配,则会引发 InquisitionError
异常。 [3]
此外,必须指定函数调用结果类型。如果调用的结果不具有声明的类型,则会引发 InquisitionError
。注意:结果的声明符不应与函数对象的声明符混淆(参见下面的示例)。
仅读取而不赋值的名称后面的类型声明符不是严格必需的,但无论如何都会被强制执行(参见 Python 禅宗:“显式优于隐式。”)。
类型与声明符之间的映射不是静态的。它可以由程序员完全自定义,但为了方便起见,某些内置类型有一些预定义的映射
类型 | 声明符 |
---|---|
object |
� (替换字符) |
int |
ℕ (双线大写 N) |
float |
℮ (估计符号) |
bool |
✓ (复选标记) |
complex |
ℂ (双线大写 C) |
str |
✎ (右下角铅笔) |
unicode |
✒ (黑色笔尖) |
tuple |
⒯ (带括号的小写拉丁字母 T) |
list |
♨ (温泉) |
dict |
⧟ (双端多映射) |
set |
∅ (空集) (注意:这也适用于完整集) |
frozenset |
☃ (雪人) |
datetime |
⌚ (手表) |
function |
ƛ (带撇号的小写拉丁字母 lambda) |
generator |
⚛ (原子符号) |
Exception |
⌁ (电箭头) |
None
类型的声明符是零宽度空格。
这些字符对每个程序员来说都应该是显而易见、易于记忆和输入的。
Unicode 替换单元
由于即使在我们现代的全球化世界中,仍然有一些老派的叛逆者无法或不想在他们的源代码中使用 Unicode,并且由于 Python 是一种宽容的语言,因此为这些人提供了一种备用方案
他们可以使用 name${UNICODE NAME OF THE DECLARATOR}$
而不是单个 Unicode 字符。例如,这两个函数定义是等效的
def fooƛ(xℂ):
return None
以及
def foo${LATIN SMALL LETTER LAMBDA WITH STROKE}$(x${DOUBLE-STRUCK CAPITAL C}$):
return None${ZERO WIDTH NO-BREAK SPACE}$
这仍然易于阅读,并将类型注释 Python 的全部功能提供给 ASCII 信徒。
The typedef
语句
可以使用此新语句扩展类型与声明符之间的映射。
语法如下
typedef_stmt ::= "typedef" expr DECLARATOR
其中 expr
解析为一个类型对象。为了方便起见,typedef
语句也可以与 class
语句混合使用,用于新类,如下所示
typedef class Foo☺(object�):
pass
示例
这是标准的 os.path.normpath
函数,已转换为类型声明语法
def normpathƛ(path✎)✎:
"""Normalize path, eliminating double slashes, etc."""
if path✎ == '':
return '.'
initial_slashes✓ = path✎.startswithƛ('/')✓
# POSIX allows one or two initial slashes, but treats three or more
# as single slash.
if (initial_slashes✓ and
path✎.startswithƛ('//')✓ and not path✎.startswithƛ('///')✓)✓:
initial_slashesℕ = 2
comps♨ = path✎.splitƛ('/')♨
new_comps♨ = []♨
for comp✎ in comps♨:
if comp✎ in ('', '.')⒯:
continue
if (comp✎ != '..' or (not initial_slashesℕ and not new_comps♨)✓ or
(new_comps♨ and new_comps♨[-1]✎ == '..')✓)✓:
new_comps♨.appendƛ(comp✎)
elif new_comps♨:
new_comps♨.popƛ()✎
comps♨ = new_comps♨
path✎ = '/'.join(comps♨)✎
if initial_slashesℕ:
path✎ = '/'*initial_slashesℕ + path✎
return path✎ or '.'
如您所见,类型声明增加了表达能力,同时使代码看起来更加专业。
兼容性问题
要启用类型声明模式,必须编写
from __future__ import type_declarations
这将启用源代码的 Unicode 解析 [4],使 typedef
成为关键字,并强制对所有赋值和函数调用进行正确的类型检查。
拒绝
经过仔细考虑、认真反省、咬牙切齿和撕心裂肺之后,我们决定拒绝本 PEP。
参考资料
致谢
衷心感谢 Armin Ronacher、Alexander Schremmer 和 Marek Kubica,他们帮助找到了最合适和最具助记的内置类型声明符。
还要感谢 Unicode 联盟将所有这些有用的字符包含在 Unicode 标准中。
版权
本文档已置于公有领域。
来源:https://github.com/python/peps/blob/main/peps/pep-3117.rst
上次修改时间:2023 年 9 月 9 日 17:39:29 GMT