Python 生成器与列表理解冲突

标签 python scope functional-programming generator

我一直在 Python 中使用生成器函数。我想编写一个函数,它接受一个值为元组的生成器,并返回一个生成器列表,其中每个生成器的值对应于原始元组中的一个索引。

目前,我有一个函数可以为元组中的一定数量的元素完成此操作。这是我的代码:

import itertools

def tee_pieces(generator):
    copies = itertools.tee(generator)
    dropped_copies = [(x[0] for x in copies[0]), (x[1] for x in copies[1])]
    # dropped_copies = [(x[i] for x in copies[i]) for i in range(2)]
    return dropped_copies

def gen_words():
    for i in "Hello, my name is Fred!".split():
        yield i

def split_words(words):
    for word in words:
        yield (word[:len(word)//2], word[len(word)//2:])

def print_words(words):
    for word in words:
        print(word)

init_words = gen_words()
right_left_words = split_words(init_words)
left_words, right_words = tee_pieces(right_left_words)
print("Left halves:")
print_words(left_words)
print("Right halves:")
print_words(right_words)

这正确地拆分了生成器,导致包含左半部分的 left_words 和包含右半部分的 right_words。

当我尝试使用上面注释掉的行来参数化要创建的生成器的数量时,问题就来了。据我所知,它应该是等效的,但是当我改用该行时,left_words 和 right_words 最终都包含单词的右半部分,输出如下:

Left halves:
lo,
y
me
s
ed!
Right halves:
lo,
y
me
s
ed!

为什么会这样?如何实现期望的结果,即参数化将生成器拆分成的 block 数?

最佳答案

这与 python's lexical scoping 有关规则。证明它的经典“令人惊讶”的例子:

funcs = [ lambda: i for i in range(3) ]
print(funcs[0]())
=> 2  #??
print(funcs[1]())
=> 2  #??
print(funcs[2]())
=> 2

您的示例是相同规则的另一个结果。

要修复,您可以使用附加函数“打破”作用域:

def make_gen(i):
    return (x[i] for x in copies[i])
dropped_copies = [make_gen(i) for i in range(2)]

这会将 i 的值绑定(bind)到传递给特定调用 make_gen 的特定值,从而实现所需的行为。没有它,它会绑定(bind)“名为 i 的变量的当前值”,它最终会成为您创建的所有生成器的相同值(因为只有一个名为 i 的变量)。

关于Python 生成器与列表理解冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31531919/

相关文章:

python - 删除以开发模式安装的 python 模块

c++ - 类静态变量初始化顺序

javascript - AngularJS 中 ng-include 内的范围丢失

java - Kotlin/Java 在 map 中收集 map 的功能和不可变方式

python - Virtualenv 正在安装错误版本的 Python

python - 使用pyqtgraph绘图而不显示

c++ - 职能范围是什么意思?

scala - 这种提升功能有名字吗?

functional-programming - 如何在 Scheme 中仅使用 1 个列表来构建 2 个列表?

python - dlltool:无法创建 .lib 文件:libpython27.a:无效的 bfd 目标