Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 增强提案

PEP 3142 – 为生成器表达式添加“while”子句

作者:
Gerald Britton <gerald.britton at gmail.com>
状态:
拒绝
类型:
标准轨迹
创建:
2009 年 1 月 12 日
Python 版本:
3.0
历史记录:

决议:
Python-Dev 消息

目录

摘要

本 PEP 提出对生成器表达式的增强,为其添加一个“while”子句,以补充现有的“if”子句。

基本原理

生成器表达式 (PEP 289) 是一种简洁的方法,用于将动态生成的物体提供给列表推导 (PEP 202)。当前的生成器表达式允许使用“if”子句来过滤返回的对象,只返回符合某些条件的对象。但是,由于“if”子句会对可能返回的每个对象进行评估,因此在某些情况下,可能会在某个点之后拒绝所有对象。例如

g = (n for n in range(100) if n*n < 50)

它等效于使用生成器函数 (PEP 255)

def __gen(exp):
    for n in exp:
        if n*n < 50:
            yield n
g = __gen(iter(range(10)))

将产生 0、1、2、3、4、5、6 和 7,但也会考虑从 8 到 99 的数字,并拒绝它们,因为 n*n >= 50 对于该范围内的数字。允许使用“while”子句将允许对冗余测试进行短路

g = (n for n in range(100) while n*n < 50)

也将产生 0、1、2、3、4、5、6 和 7,但在 8 处停止,因为条件 (n*n < 50) 不再为真。这将等效于生成器函数

def __gen(exp):
    for n in exp:
        if n*n < 50:
            yield n
        else:
            break
g = __gen(iter(range(100)))

目前,为了获得相同的结果,需要编写一个像上面的生成器函数,或者使用 itertools 中的 takewhile 函数

from itertools import takewhile
g = takewhile(lambda n: n*n < 50, range(100))

takewhile 代码实现了与所提议语法相同的结果,尽管以更长(有些人会说“不那么优雅”)的方式。此外,takewhile 版本需要额外的函数调用(上面示例中的 lambda),以及相关的性能损耗。一个简单的测试表明

for n in (n for n in range(100) if 1): pass

for n in takewhile(lambda n: 1, range(100)): pass

的性能大约高出 10%,尽管它们实现的结果相似。(第一个示例使用生成器;takewhile 是一个迭代器)。如果以类似的方式实现,“while”子句的性能应该与现在的“if”子句大致相同。

读者可能会问“if”和“while”子句是否应该是互斥的。有很多很好的例子表明,在某些时候,两者都可以发挥很好的作用。例如

p = (p for p in primes() if p > 100 while p < 1000)

应该返回在 100 到 1000 之间找到的素数,假设我有一个 primes() 生成器,它会产生素数。

为生成器表达式添加“while”子句保留了紧凑的形式,同时添加了用于短路表达式的有用工具。

致谢

Raymond Hettinger 在 2002 年 1 月首次提出生成器表达式的概念。


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

最后修改时间: 2023-09-09 17:39:29 GMT