Python 的迭代器和生成器:仍未完全理解

Python’s Iterators and Generators: Still Not Fully Understood

import random

my_list = [random.randint(3, 100) for i in range(4)]

def is_even(some_list):
    for i in some_list:
        if i % 2 == 0:
            yield True
        else:
            yield False

print(my_list)
print(list(is_even(my_list)))

>>> [94, 53, 27, 42]
>>> [True, False, False, True]

看来我还是没有完全理解这个概念。在每次迭代中,is_even 函数相应地产生 TrueFalse。我看不出这些“收益”是如何累积的。 (或者,我看不到它们是如何在每次迭代结束时附加到最终列表的。例如,在给定的示例中,第一次迭代产生 True,然后第二次迭代开始。第一个在哪里True 保留值?)那里到底发生了什么?

我想我明白你的意思了:

每次 is_even 是 运行,它会检查列表中的每个数字,然后 returns 判断真假(我相信您已经知道)。当您使用 'print(list(is_even(my_list)))' 时,过程非常简单 - 您正在创建函数 'is_even' 返回的每个结果的列表,其顺序与 for 循环之前处理它们的顺序相同。

希望对您有所帮助。

您可以将迭代器理解为一个列表,在您请求它们之前,其所有元素都未填充。如果您实例化一个带有迭代器作为参数的列表,就像您在此指令 list(is_even(my_list)) 中所做的那样,您将立即将其所有元素取出到内存中,这不是我们在使用迭代器时想要的,因为它更有效只有最后一个元素要检查而不是整个事情,对吗?所以尝试像这样一次迭代一次:

for item in iterator:

或使用next()方法。

从一开始就以您为榜样:

my_list = [random.randint(3, 100) for i in range(4)]

这是 list comprehension 的一个很好的例子。这只是一种更简洁的写法:

my_list = []
for i in range(4):
    my_list.append(random.randint(3, 100))

接下来,你定义一个generator function:

def is_even(some_list):
    for i in some_list:
        if i % 2 == 0:
            yield True
        else:
            yield False

生成器函数可以像迭代器一样运行。值 "yielded" 按需提供。您可以将其想象成 流式传输结果 .

的函数
print(list(is_even(my_list)))

此时发生了一些事情,让我们将它们分开以便更好地了解正在发生的事情:

>>> g = is_even(my_list)

is_even(my_list) 不是 return 列表,正如您所期望的那样,而是 generator:

>>> g
... <generator object is_even at ...>
>>> type(g)
... generator

list 构造接受一个 iterable 作为参数,一个 generatoriterable。当构建实际列表时,您的 产生 值实际上是在这一步累积的:

>>> l = list(g)
>>> print(l)
... [True, False, False, True]

回答您的问题:累积魔术发生在 list 构造函数内部 - 事实上,将项目累积到列表中正是它的工作。当你写:

print(list(is_even(my_list)))

is_even(...) 返回的对象有一个 next() 方法,该方法提供生成器产生的下一个值,或者在没有更多值可用时引发异常。 list 函数是将这些值累积到列表中的函数,该列表最终返回。

你可以想象 list 是一个这样定义的函数:

def list(iter):
    accum = []
    # the following loop is an approximate expansion of
    # for item in iter: accum.append(item)
    while 1:
        try:
            # get the next yielded value from generator
            item = iter.next()
        except StopIteration:
            # no more values
            break
        accum.append(item)
    return accum

在你的例子中,list 被赋予一个生成器,for 循环正在耗尽生成器并在隐藏的临时列表中累积单个元素。正是这个临时列表,上面实现中的 accum,保存了第一个 True 值,并继续存储后续值。一旦生成器耗尽,整个累积列表将返回给调用者。