发电机未按预期关闭数据

2024-05-15 13:05:55 发布

您现在位置:Python中文网/ 问答频道 /正文

对不起,如果标题写得不好,我不知道该怎么说。我有一个函数,基本上是在二维iterable的第二维上迭代。下面是一个简单的复制品:

words = ['ACGT', 'TCGA']

def make_lists():
    for i in range(len(words[0])):
        iter_ = iter([word[i] for word in words])
        yield iter_

lists = list(make_lists())

for list_ in lists:
    print(list(list_))

运行此输出:

['A', 'T']
['C', 'C']
['G', 'G']
['T', 'A']

我希望生成生成器,而不必计算words,因为words非常长,所以我尝试了以下方法:

words = ['ACGT', 'TCGA']

def make_generators():
    for i in range(len(words[0])):
        gen = (word[i] for word in words)
        yield gen

generators = list(make_iterator())

for gen in generators:
    print(list(gen))

但是,运行输出:

['T', 'A']
['T', 'A']
['T', 'A']
['T', 'A']

我不确定到底发生了什么。我怀疑这与生成器在屈服时没有关闭其作用域有关,所以它们都是共享的。如果我在一个单独的函数中创建生成器,并从该函数中产生返回,它似乎可以工作。你知道吗


Tags: 函数informakedefrangelistslist
1条回答
网友
1楼 · 发布于 2024-05-15 13:05:55

i现在是这些生成器的自由变量,它们将使用它的最后一个值,即3。简单地说,它们知道应该从哪里获取i的值,但不知道创建时i的实际值。比如说:

def make_iterator():
    for i in range(len(words[0])):
        gen = (word[i] for word in words)
        yield gen
    i = 0  # Modified the value of i 

将导致:

['A', 'T']
['A', 'T']
['A', 'T']
['A', 'T']

生成器表达式被实现为函数作用域,另一方面,列表理解会立即运行,并且可以在迭代过程中获取i的值(在python3中,列表理解被实现为函数作用域,但不同的是它们不是懒惰的)

修复方法是使用一个内部函数,使用默认参数值捕获每个循环中i的实际值:

words = ['ACGT', 'TCGA']

def make_iterator():
    for i in range(len(words[0])):
        # default argument value is calculated at the time of
        # function creation, hence for each generator it is going
        # to be the value at the time of that particular iteration  
        def inner(i=i):
            return (word[i] for word in words)
        yield inner()

generators = list(make_iterator())

for gen in generators:
    print(list(gen))

您可能还想阅读:

相关问题 更多 >