PEP 3152 – 协函数
- 作者:
- Gregory Ewing <greg.ewing at canterbury.ac.nz>
- 状态:
- 已拒绝
- 类型:
- 标准轨迹
- 创建:
- 2009年2月13日
- Python 版本:
- 3.3
- 历史记录:
摘要
本提案提出了一种用于定义和调用一种称为“协函数”的特殊类型的生成器的语法。它旨在提供一种简化的方法来编写基于生成器的协程,并允许尽早检测在编写此类代码时容易出现的某些类型的错误,否则这些错误往往会导致难以诊断的症状。
此提案建立在 PEP 380 中描述的“yield from”机制的基础上,并根据它描述了协函数的一些语义。但是,如果需要,可以独立于PEP 380来定义和实现协函数。
拒绝理由
参见 https://mail.python.org/pipermail/python-dev/2015-April/139503.html
规范
协函数定义
引入了一个新的关键字codef
,它用于代替def
来定义协函数。协函数是一种特殊的生成器,具有以下特征
- 协函数始终是生成器,即使它不包含任何
yield
或yield from
表达式。 - 不能像普通函数那样调用协函数。如果尝试对协函数进行普通调用,则会引发异常。
协调用
从一个协函数到另一个协函数的调用是通过用一个新的关键字cocall
标记调用来完成的。表达式
cocall f(*args, **kwds)
在语义上等价于
yield from f.__cocall__(*args, **kwds)
除了由 __cocall__ 返回的对象预计是迭代器,因此跳过了对其调用 iter() 的步骤。
协调用表达式的完整语法由以下语法行描述
atom: cocall | <existing alternatives for atom>
cocall: 'cocall' atom cotrailer* '(' [arglist] ')'
cotrailer: '[' subscriptlist ']' | '.' NAME
cocall
关键字仅在协函数内部才在语法上有效。如果在任何其他上下文中使用它,则会导致 SyntaxError。
实现 __cocall__ 的对象应返回一个遵守迭代器协议的对象。协函数对 __cocall__ 的响应方式与普通生成器函数对 __call__ 的响应方式相同,即返回一个生成器迭代器。
某些包装其他可调用对象的物体,特别是绑定方法,将被赋予 __cocall__ 实现,这些实现将委托给底层对象。
新的内置函数、属性和 C API 函数
为了便于协函数与非协程代码的交互,将有一个内置函数costart
,其定义等价于
def costart(obj, *args, **kwds):
return obj.__cocall__(*args, **kwds)
还将有一个相应的 C API 函数
PyObject *PyObject_CoCall(PyObject *obj, PyObject *args, PyObject *kwds)
目前尚未确定协函数是否是一种不同的对象类型,或者像生成器函数一样,仅仅是一个带有特殊标记的函数实例。如果是后者,则应提供一个只读布尔属性__iscofunction__
来允许测试给定的函数对象是否为协函数。
动机和基本原理
当用于将生成器的一部分工作委托给另一个函数时,yield from
语法相当容易理解。它也可以有效地用于实现基于生成器的协程,但在用于此目的时,它读起来有些别扭,并且往往会掩盖代码的真正意图。
此外,使用生成器作为协程在某种程度上容易出错。如果忘记在应该使用 yield from
的地方使用它,或者在不应该使用它的地方使用它,则产生的症状可能难以理解和令人困惑。
最后,有时需要一个函数成为协程,即使它不产生任何东西,在这种情况下,有必要采用诸如if 0: yield
之类的技巧来强制它成为生成器。
codef
和cocall
结构通过使语法直接反映意图(即该函数构成协程的一部分)来解决第一个问题。
第二个问题是通过使协程代码和非协程代码以不合理的方式混合变得不可能来解决的。如果规则被违反,则会引发一个异常,该异常准确地指出问题是什么以及在哪里。
最后,通过使定义形式确定函数是否为协程,而不是它包含的内容,消除了对虚拟 yield 的需要。
原型实现
Python 3.1.2 的补丁形式的实现可以在这里找到
http://www.cosc.canterbury.ac.nz/greg.ewing/python/generators/cofunctions.html
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-3152.rst