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
函数相应地产生 True
或 False
。我看不出这些“收益”是如何累积的。 (或者,我看不到它们是如何在每次迭代结束时附加到最终列表的。例如,在给定的示例中,第一次迭代产生 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
作为参数,一个 generator
是 iterable
。当构建实际列表时,您的 产生 值实际上是在这一步累积的:
>>> 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
值,并继续存储后续值。一旦生成器耗尽,整个累积列表将返回给调用者。
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
函数相应地产生 True
或 False
。我看不出这些“收益”是如何累积的。 (或者,我看不到它们是如何在每次迭代结束时附加到最终列表的。例如,在给定的示例中,第一次迭代产生 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
作为参数,一个 generator
是 iterable
。当构建实际列表时,您的 产生 值实际上是在这一步累积的:
>>> 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
值,并继续存储后续值。一旦生成器耗尽,整个累积列表将返回给调用者。