PEP 3107(功能注释)

大家好。我决定完全理解Python注释,同时翻译一系列记录该主题的PEP。我们将从3.X标准开始,以python 3.8的创新结束。我必须马上说,这个PEP是最基本的PEP之一,它的阅读内容仅对初学者有用。好吧,让我们开始吧:


PEP 572-功能注释

p3107
标题:功能注释
作者:柯林·温特<collinwinter在google.com>,托尼·朗兹<tony at lownds.com>
状态:最后
一种:标准
创建时间:2006年12月2日
Python版本:3.0

标准注释


该PEP引入了用于在Python函数中添加任意注释(元数据)的语法。

理由


Python 2.x中的函数没有内置的方法来注释参数和返回值。为了解决这一差距,出现了许多工具和库。其中一些使用PEP 318中描述的装饰器,而其他一些则分析文档字符串功能并在其中查找信息。

此PEP旨在提供一种单一的标准方法来对功能进行注释,以减少到目前为止由于机制和语法的广泛差异而引起的混乱。

功能注释基础


在开始讨论Python 3.0功能注释之前,让我们首先以笼统的术语来讨论它们的功能:

  1. 函数的参数和返回值的注释是完全可选的。
  2. 注释无非是在编译时将任意表达式与函数的不同部分相关联的一种方法。

    Python本身不对注解给予任何关注。唯一的是,它允许您访问它们,这在下面的“获得对功能注释的访问”部分中进行了描述。

    仅当由第三方库解释时,注释才有意义。他们可以使用功能注释执行任何所需的操作。例如,一个库可以使用字符串注释来提供改进的参考数据,例如:

    def compile(source: "something compilable",
                filename: "where the compilable thing comes from",
                mode: "is this a single statement or a suite?"):
        ...

    另一个库可能使用Python函数和方法注释来检查类型匹配。该库可以使用批注显示期望的输入数据类型和返回的数据类型。也许会是这样的:

    def haul(item: Haulable, *vargs: PackAnimal) -> Distance:
        ...

    我们再重复一遍:所有示例本身的注释都没有任何意义。只有与第三方库结合使用,它们才具有真正的意义。
  3. 如第2段所述,该PEP不会尝试引入任何标准机制来处理注释,即使对于内置类型也是如此。所有这些工作都分配给第三方库。

句法


参量


参数注释是参数本身名称之后的可选表达式:

def foo (a: , b:  = 5):
    ...

在伪语法中,参数现在看起来像:parameter [:expression] [= expression]也就是说,注释(如默认值)是可选的,并且始终在后者之前。就像等号用于表示默认值一样,冒号用于注释。执行功能定义时,将评估所有注释表达式(如默认值)。获取“额外”参数(即* args和** kwargs)具有相同的语法:

def foo(*args: expression, **kwargs: expression):
    ...

嵌套参数的注释始终跟随参数名称,而不是最后一个括号。不需要在嵌套参数中注释每个“名称”:

def foo((x1, y1: expression),
        (x2: expression, y2: expression)=(None, None)):
    ...

返回值


到目前为止,我们还没有提供如何在函数中注释返回类型的示例。这样做是这样的:

def sum() -> expression:
    ...

也就是说,文字->和某种表达式现在可以跟随参数列表。像参数注释一样,执行函数定义时将评估此表达式。

现在,函数声明的完整语法如下:

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
funcdef: [decorators] 'def' NAME parameters ['->' test] ':' suite
parameters: '(' [typedargslist] ')'
typedargslist: ((tfpdef ['=' test] ',')*
                ('*' [tname] (',' tname ['=' test])* [',' '**' tname]
                 | '**' tname)
                | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
tname: NAME [':' test]
tfpdef: tname | '(' tfplist ')'
tfplist: tfpdef (',' tfpdef)* [',']

Lambdas


Lambda函数不支持注释。当然,可以通过添加“包装”方括号中的参数的功能来纠正语法,但是决定不进行此类更改,因为:

  1. 这将违反向后兼容性。
  2. Lambda是中性的,并且根据定义是匿名的
  3. Lambda总是可以重写为函数


获取对功能注释的访问


编译后,可以通过__annotations__属性使用功能注释。这个属性是一个可变的字典,用于比较变量名称和指示给它们的注释的值。

__annotations__字典具有特殊的“返回”键。仅当还为函数的返回值定义了注释时,此键才存在。例如,以下注释:

def foo (a: 'x', b: 5 + 6, c: list) -> max (2, 9):
    ...

将通过__annotations__属性返回为:

{'a': 'x',
 'b': 11,
 'c': list,
 'return': 9}

选择键名“ return”是因为它不能与参数名冲突(任何使用return作为参数名的尝试都会导致SyntaxError异常)。

如果该函数没有注释,或者该函数是通过lambda表达式创建的,则__annotations__属性将为空。

用例


在讨论注释期间,我们研究了几种使用注释的方法。其中一些在此处显示,并根据传输信息的“类别”进行分组。这里还包括可以使用注释的现有产品和软件包的示例。

  • 提供类型信息
    • 类型检查
    • 有关预期和返回的参数类型的IDE技巧
    • 函数重载/泛型函数[约 函数重载在其他语言中很普遍,它包含多个具有相同名称的函数,但同时,它们所接受的参数数量有所不同]
    • 不同编程语言之间的桥梁
    • 适应
    • 谓词逻辑功能
    • 映射数据库查询
    • RPC参数封送[大约 封送处理是将存储在RAM中的信息转换为适合于存储或传输的格式的过程。RPC-远程过程调用]
  • 提供其他信息
    • 记录参数和返回值

标准库


Pydoc和检查模块


pydoc模块将在功能参考信息中显示注释。检查模块将更改并支持注释。

链接到其他PEP


功能签名对象


功能签名对象必须提供功能注释。参数对象等可能会发生变化。[大约 函数的签名(Signature)-它的一般声明的一部分,允许翻译手段在其中识别该函数]

实作


参考实现作为修订号53170包含在py3k分支(以前为“ p3yk”)中

拒绝报价


  • BDFL [. ] , , : « »
  • stdlib , , . .
  • , , .
  • 尽管有进一步的讨论,但决定不对注释交互的机制进行标准化。在现阶段达成这样的协议还为时过早。我们希望允许这些协议根据实际情况有机地发展,而不是试图强迫每个人使用某种人为的计划。

All Articles