PEP 201 – 锁步迭代

猫勺猫勺 04-23 67 阅读 0 评论

介绍

PEP 描述了“锁步迭代”提案。此 PEP 跟踪 此功能的状态和所有权,计划在 蟒蛇 2.0。它包含对功能和轮廓的描述 支持该功能所需的更改。本 PEP 总结了 在邮件列表论坛中进行的讨论,并提供进一步的 URL 信息(如适用)。此文件的 CVS 修订历史记录 包含权威的历史记录。

赋予动机

Python 中的标准 for 循环遍历序列中的每个元素 直到序列用尽 。但是,for 循环会遍历 只有一个序列,并且通常需要循环更多 而不是一个锁步方式的序列。换句话说,在某种程度上 这样,通过循环的第 i 次迭代返回一个对象 包含每个序列中的第 i 个元素。

用于实现此目的的常见习语是不直观的。这个PEP 提出了一种执行此类迭代的标准方法,方法是引入 新的内置函数称为 。zip

虽然 zip() 的主要动机来自锁步迭代, 通过将 zip() 实现为内置函数,它具有额外的 在 for 循环以外的上下文中的实用程序。

锁步 for 循环

锁步 for 循环是两个或多个非嵌套迭代 序列,使得在每次通过循环时,一个元素来自 采用每个序列来组成目标。此行为可以 已经通过使用 map() 内置的 Python 完成 功能:

>>> a = (1, 2, 3)
>>> b = (4, 5, 6)
>>> for i in map(None, a, b): print i
...
(1, 4)
(2, 5)
(3, 6)
>>> map(None, a, b)
[(1, 4), (2, 5), (3, 6)]

for 循环只是像往常一样循环访问此列表。

虽然 map() 成语在 Python 中很常见,但它有几个 弊:

  • 对于没有函数式编程的程序员来说,这是不明显的 背景。

  • 魔术第一论点的使用是不明显的。None

  • 当 列表的长度不同:较短的序列是 填充:None

>>> c = (4, 5, 6, 7)
>>> map(None, a, c)
[(1, 4), (2, 5), (3, 6), (None, 7)]

由于这些原因,Python 2.0 中提出了几个建议 锁步 for 循环的语法支持的 beta 时间框架。这里是 两点建议:

for x in seq1, y in seq2:
  # stuff
for x, y in seq1, seq2:
  # stuff

这两种形式都行不通,因为它们都已经意味着 Python 中的某些内容和更改含义会破坏现有内容 法典。所有其他关于新语法的建议都遇到了同样的问题, 或与其他名为“列表”的其他提议功能发生冲突 理解“(见 PEP 202)。

建议的解决方案

建议的解决方案是引入一个新的内置序列 发电机功能,在模块中可用。这 函数将被调用,并具有以下签名:__builtin__zip

zip(seqa, [seqb, [...]])

zip()采用一个或多个序列并编织它们的元素 一起,就像相等的序列一样 长度。当最短序列用尽时,编织停止。map(None, ...)

返回值

zip()返回一个真正的 Python 列表,同样的方式。map()

例子

下面是一些示例,基于下面的参考实现:

>>> a = (1, 2, 3, 4)
>>> b = (5, 6, 7, 8)
>>> c = (9, 10, 11)
>>> d = (12, 13)

>>> zip(a, b)
[(1, 5), (2, 6), (3, 7), (4, 8)]

>>> zip(a, d)
[(1, 12), (2, 13)]

>>> zip(a, b, c, d)
[(1, 5, 9, 12), (2, 6, 10, 13)]

请注意,当序列的长度相同时,为 可逆:zip()

>>> a = (1, 2, 3)
>>> b = (4, 5, 6)
>>> x = zip(a, b)
>>> y = zip(*x) # alternatively, apply(zip, x)
>>> z = zip(*y) # alternatively, apply(zip, y)
>>> x
[(1, 4), (2, 5), (3, 6)]
>>> y
[(1, 2, 3), (4, 5, 6)]
>>> z
[(1, 4), (2, 5), (3, 6)]
>>> x == z
1

当序列不是时,不可能以这种方式反向压缩 长度都一样。

参考实现

这是一个参考实现,在 Python 中内置了 zip() 功能。这将在最终之后替换为 C 实现 批准:

def zip(*args):
    if not args:
        raise TypeError('zip() expects one or more sequence arguments')
    ret = []
    i = 0
    try:
        while 1:
            item = []
            for s in args:
                item.append(s[i])
            ret.append(tuple(item))
            i = i + 1
    except IndexError:
        return ret

BDFL声明

注意:BDFL 指的是 Guido van Rossum,Python 的仁慈者 终身独裁者。

  • 函数的名称。此 PEP 的早期版本包括 未解决的问题列表 20+ 建议的替代名称。在 面对没有压倒性的更好选择,BDFL强烈 由于其 Haskell [2] 遗产而更受欢迎。请参阅版本 1.7 此 PEP 的替代方案列表。zip()zip()

  • zip()应为内置函数。

  • 可选填充。该 PEP 的早期版本提出了一个 可选的关键字参数,当 参数序列的长度不同。这是相似的 行为到语义,但用户除外 将能够指定 pad 对象。这已被 BDFL 赞成始终截断到最短的序列,因为 KISS原则。如果真的有需要,添加起来会更容易 后。如果不需要,仍然无法删除 它在未来。padmap(None, ...)

  • 懒惰的评估。此 PEP 的早期版本建议返回一个执行延迟评估的内置对象 使用协议。这遭到了强烈反对 由 BDFL 支持返回真正的 Python 列表。如果懒惰 将来需要评估,BDFL 建议添加一个功能。zip()__getitem__()xzip()

  • zip()没有参数。BDFL强烈希望这次加息。 TypeError 异常。

  • zip()用一个参数。BDFL 强烈希望这样做 返回 1 元组的列表。

  • 内箱和外箱控制。此 PEP 的早期版本 包含对某些人的功能的相当冗长的讨论 想要的,即控制内在和外在的能力 容器类型是(它们分别是元组和列表,在此 PEP的版本)。鉴于简化的 API 和实现, 这种阐述被拒绝了。有关更详细的分析,请参阅 此 PEP 的 1.7 版。

后续更改为

在 Python 2.4 中,没有参数的 zip() 被修改为返回一个空的 列表,而不是引发 TypeError 异常。基本原理 最初的行为是,没有论据被认为是 指示编程错误。然而,这种想法并没有 预期将 zip() 与运算符一起使用以进行解包 可变长度参数列表。例如,zip 的反面可以 定义为:。这种转变 还定义了矩阵转置或等效的行/列交换 定义为元组列表的表。后一种转变是 读取数据文件时常用的记录为行和字段 作为列。例如,代码:*unzip = lambda s: zip(*s)

date, rain, high, low = zip(*csv.reader(file("weather.csv")))

重新排列列式数据,以便将每个字段收集到 用于简单循环和汇总的单个元组:

print "Total rainfall", sum(rain)

如果处理,则使用更容易编码 作为允许的情况,而不是例外情况。这尤其 当数据从 null 构建或递归到 null 时很有帮助 没有记录的案例。zip(*args)zip(*[])

看到这种可能性,BDFL同意(有一些疑虑) 更改了 Py2.4 的行为。

其他更改

  • 上面讨论的函数是在 Py2.3 中实现的 模块为 .此函数 提供懒惰行为,消耗单个元素并产生 每个传递上的单个元组。“即时”风格可节省内存 并且比基于列表的对应项运行得更快。xzip()itertoolsitertools.izip()zip()

  • 该模块还添加了 和 .这些工具可以一起用于垫 序列 (以匹配 的行为):itertoolsitertools.repeat()itertools.chain()Nonemap(None, seqn)

    zip(firstseq, chain(secondseq, repeat(None)))

版权

文档已置于公共领域。


The End 微信扫一扫

文章声明:以上内容(如有图片或视频在内)除非注明,否则均为腾龙猫勺儿原创文章,转载或复制请以超链接形式并注明出处。

本文作者:猫勺本文链接:https://www.jo6.cn/post/87.html

上一篇 下一篇

相关阅读

发表评论

访客 访客
快捷回复: 表情:
评论列表 (暂无评论,67人围观)

还没有评论,来说两句吧...

取消
微信二维码
微信二维码
支付宝二维码