PEP 3107 -- 函数注解
Meta
- Python 版本:3.0
- 发布时间:2006-12-02
- 原文链接:PEP 3107 – Function Annotations
- 翻译日期:2023-11-11
- 翻译作者:联系或纠错
摘要
该 PEP 引入了一个为 Python 的函数 [1] (可调用对象)添加任意元数据注解的语法
理由
由于 Python 2.x 缺少一个对函数参数和返回值注解的标准语法,各种工具或库的出现填补了这一空白,有些利用了 PEP 318 中引入的装饰器,还有一些则通过解析函数的文档注释,寻找其中的注释来实现。
本 PEP 的目的是为这些信息提供一个唯一、标准的方法,减少由于机制和语法的巨大差异而造成的困惑
函数注释基础
在开始讨论 Python3.0 函数注解的确切来龙去脉之前,我们先从管以上谈谈什么是注解,什么不是注解:
函数注解,无论是参数还是返回值,都是可选的
函数注解只不过是在编译时将独立的 Python 表达式与函数任意部分关联起来的一种方式
就其本身而言,Python 并没有为注解添加任何特定的含义或意义,就起本身而言,Python 只是单纯的让下文中访问函数注解的表达式可用。
注解具有的唯一意义是能够被第三方库所解释。注解的使用者能够用这些函数注解作任何它们想做的事情。例如,一个库可能使用基于字符串的注解来提供帮助信息。如下所示:
1
2
3
4def compile(source: "something compilable",
filename: "where the compilable thing comes from",
mode: "is this a single statement or a suite?"):
...另一个库可能用来对 Python 的函数或方法提供类型检查,这个库能够使用注解来提示期待的输入和输出的类型,可能像下面这样:
1
2def hula(item: Hualable, *vargs: PackAnimal) -> Distance:
...然后,无论是第一个示例中的字符串,还是第二个示例中的类型信息本身都没有任何含义,这些含义仅取决于三方库
基于第 2 点,这个 PEP 没有尝试引入任何标准的语法,即使是内置类型也是如此,这项工作将留给第三方库
语法
参数
参数的注解采用跟在参数后面的可选表达式的形式:
1 | def foo(a: expression, b: expression = 5): |
在伪语法中,参数现在形如 identifier [: expression] [= expression]
。也就是说,注解始终位于默认值的前面,并且注解和默认值都是可选的。就像用等号表示默认值一样,冒号用来标识注解。所有的注解表达式都会在函数定义时被执行,就像默认值表达式一样。
多余参数 (如:*args
和 **kwargs
) 的注解也以类似的方式标识:
1 | def foo(*args: expression, **kwargs: expression): |
嵌套参数的注解始终跟在参数名称后面,而不是最后一个括号后面,不需要对签到参数的所有参数进行注解:
1 | def foo((x1, y1: expression), |
返回值
这些示例到目前为止忽略了函数返回值类型注解。具体做法如下:
1 | def sum() -> expression: |
也就是说,现在参数列表后面可以跟随一个字面的 ->
符号和一个 Python 的表达式,与参数注解一样,这个表达式将会在函数定义的时候被执行。
现在函数定义 [11] 的语法是:
1 | decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE |
匿名函数
lambda
的语法不支持注解,可以改变 lambda
的语法,要求在参数列表周围加上括号来支持注解,但是,决定 [12] 不进行这个修改,因为:
- 这是一个不兼容的修改
- lambda 总是被精简过的
- lambda 总是可以修改为一个函数
访问函数注解
编译后,一个函数的注解始终可以通过函数的 __annotations__
属性来获得。这个属性是一个可变字典,参数名称将会映射到一个注解表达式执行的对象上。
__annotations__
映射中有一个特殊的键 return
。这个键只有为函数返回值提供注解的时候才会存在。
例如,存在一下注解:
1 | def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9): |
那么,__annotations__
将会是:
1 | { |
之所以选择 return
作为键,是因为它不会与参数名称冲突,任何尝试将 return
作为参数名称的函数都将报 SyntaxError
的错误。
如果函数没有任何注解或者函数从 lambda
创建的,那么 __annotations__
会是一个空的可变字典
使用案例
在讨论注解的过程中,有一些案例被提出来了。这里介绍了一些,它们按照传达的信息进行了分类。还包含了一些使用了注解的现有的产品或包的示例。
- 提供类型信息
- 其他信息
- 参数和返回值文档 ([23])
标准库
pydoc 和 inspect
pydoc
模块应该在显示函数帮助的时候同时显示函数的注解
inspect
模块应该进行修改来支持注解
关联的其他 PEP
函数签名对象(PEP 362)
函数签名对象应该展示函数的注解,Parameter
对象可能需要更改或者其他的更改来保证该展示
实现
参考实现已经在 py3k (前身为 p3yk) 修改分支 53130 [10] 中完成
被拒绝的提案
- BDFL(译者注: 指被称为 Python 独裁者的 Guido Van Rossum) 以 “太难看了” 拒绝了作者关于为生成器添加注解的特殊语法的想法[2]
- 尽管在早期讨论过 ([5], [6]),但是在 stdlib 中关于生成器和高阶函数的特殊对象注解最终被拒绝,因为它更适合第三方库,将它们包含在标准库中会引发更多棘手的问题。
- 尽管对标准类型参数化语法进行了大量的讨论,最后还是决定将其留给第三方库。([7], [8], [9])。
- 尽管进行了更多的讨论,但是还是决定不对注释互操作性进制进行标准化。在这个时候将互操作性约定标准化为时尚早。我们宁可让这些惯例根据实际使用情况和需要有机的发展起来,而不是试图强迫所有用户采用某种设计好的方案。 ([13], [14], [15])
参考文献和注释
- [1] - 非特殊说明,函数指的是 Python 中的可调用对象
- [2] - https://mail.python.org/pipermail/python-3000/2006-May/002103.html
- [3] - http://web.archive.org/web/20070730120117/http://oakwinter.com/code/typecheck/
- [4] - http://web.archive.org/web/20070603221429/http://maxrepo.info/
- [5] - https://mail.python.org/pipermail/python-3000/2006-May/002091.html
- [6] - https://mail.python.org/pipermail/python-3000/2006-May/001972.html
- [7] - https://mail.python.org/pipermail/python-3000/2006-May/002105.html
- [8] - https://mail.python.org/pipermail/python-3000/2006-May/002209.html
- [9] - https://mail.python.org/pipermail/python-3000/2006-June/002438.html
- [10] - http://svn.python.org/view?rev=53170&view=rev (译者注: 该链接需要身份认证)
- [11] - http://docs.python.org/reference/compound_stmts.html#function-definitions
- [12] - https://mail.python.org/pipermail/python-3000/2006-May/001613.html
- [13]- https://mail.python.org/pipermail/python-3000/2006-August/002895.html
- [14] - https://mail.python.org/pipermail/python-ideas/2007-January/000032.html
- [15] - https://mail.python.org/pipermail/python-list/2006-December/420645.html
- [16] - http://www.python.org/idle/doc/idle2.html#Tips
- [17] - http://www.jython.org/Project/index.html
- [18] - http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython
- [19] - http://peak.telecommunity.com/PyProtocols.html
- [20] - http://www.artima.com/weblogs/viewpost.jsp?thread=155123
- [21] - http://www-128.ibm.com/developerworks/library/l-cppeak2/
- [22] - http://rpyc.wikispaces.com/
- [23] - http://docs.python.org/library/pydoc.html
版权
本文已发布在公共网络上
翻译词典
introduced
- 引入wide
- 大variation
- 更改,变异mechanism
- 机制