跳转到主要内容
模块 6 · 第 3 课(共 4)课程中的23/36~10 min
模块课程(3/4)

生成器表达式

生成器表达式类似于列表理解,但带有 圆括号而不是方括号。差异是巨大的: 它不会在内存中构建列表,它会按需生成元素, 一次一个。

Python
gen = (n * n for n in range(1_000_000))
# istantaneo, memoria costante: nessun calcolo ancora fatto

list_comp = [n * n for n in range(1_000_000)]
# alloca 1M di int in memoria

惰性(惰性评估)

在有人请求下一个值之前,生成器不会执行任何操作:

Python
gen = (n * n for n in range(5))
next(gen)    # 0    (calcolato adesso)
next(gen)    # 1
next(gen)    # 4
# ... e così via, fino a StopIteration

它会耗尽:消耗完所有元素后,它永远为空。 要重用它,您必须重新创建它。

何时使用它

当您将结果传递给按​​顺序使用它们的函数时:

Python
total = sum(n * n for n in range(1_000_000))
# nessuna lista intermedia, memoria costante

sum、any、all、max、min、"".join(...) 都接受生成器。 如果外部函数只需要调用括号,则可以 省略生成器自己的:

Python
sum((n * n for n in range(10)))    # OK
sum(n * n for n in range(10))      # IDENTICO, più leggibile

any 和 all:短路

any(...) 和 all(...) 一旦得到答案就停止迭代。 使用生成器,甚至不会计算以下元素。

Python
nums = [1, 2, 3, 4, 5]
any(n > 3 for n in nums)    # True (si ferma a 4)
all(n > 0 for n in nums)    # True
all(n > 2 for n in nums)    # False (si ferma a 1)

模式:惰性管道

Python
righe = (linea.strip() for linea in testo.splitlines())
non_vuote = (r for r in righe if r)
prime_dieci = []
for r in non_vuote:
    prime_dieci.append(r)
    if len(prime_dieci) == 10:
        break

即使投入巨大,也没有中间列表。

使用 sum、any、all 来消耗生成器

生成器表达式非常适合直接传递给使用可迭代对象的函数,例如 sum()、any() 或 all()。在这种情况下,您可以省略生成器表达式的外括号,只需编写:

Python
squares_sum = sum(x**2 for x in range(10))

这可以使您的代码保持干净并且具有很高的内存效率。

尝试一下

锻炼#python.m6.l3.e1
尝试:0加载中...

使用 sum() 中的生成器表达式计算 1 到 100(含)之间的数字的平方和。将其分配给“tot”。评估“总”。

正在加载编辑器...
显示提示

range(1, 101) 包括 100。

3 次尝试后可用的解决方案

复习练习

锻炼#python.m6.l3.e2
尝试:0加载中...

给定 `words = ['ciao', 'mondo', 'PYTHON', 'java']`,使用带有生成器表达式的 any() 来检查是否至少有一个单词是大写 (.isupper())。将结果分配给“has_uppercase”。评估“has_uppercase”。

正在加载编辑器...
显示提示

任何(p.isupper()对于单词中的p)

3 次尝试后可用的解决方案

额外的挑战

锻炼#python.m6.l3.e3
尝试:0加载中...

Use a generator expression passed directly to the `sum()` function to calculate the sum of the squares of all integers from 1 to 100 inclusive. Store the result in `total_sum` and evaluate it.

正在加载编辑器...
显示提示

编写total_sum = sum(x**2 for x in range(1, 101))。不需要双括号。

3 次尝试后可用的解决方案