与列表理解相比,生成器表达式做的工作更少吗?
Are generator expressions doing less work compared to list comprehensions?
在重构一段代码时,我注意到了这一点:
if product_id in [c["id"] for c in self.data.load_products()]:
# Do something
反过来,load_products()
执行 SQL 查询,并且对于每个产品:
- 执行一些相对 CPU 昂贵的操作和:
- 使用
yield
将产品一一return给来电者。
据我所知,列表理解和生成器表达式之间的区别在于,在列表理解的情况下,所有产品都将从数据库加载并处理,即使第一个产品是匹配的。
因此,如果我用这样的生成器表达式替换它:
# ↴ ↴
if product_id in (c["id"] for c in self.data.load_products()):
# Do something
它可以通过最终减少工作量来改进代码,即一旦找到匹配项,就不会从数据库加载下一个产品,也不会对其进行处理。
不过,我不太了解 Python 可以肯定。
我说得对吗? Python 是否会在找到匹配项后立即停止,或者两段代码会执行相同的操作并从数据库中加载每个产品?
列表理解总是运行结束并将所有结果保存在内存中。
生成器(表达式或非表达式)可以短路如果使用得当——例如if product_id in <some generator>
确实会在找到匹配项后立即停止,只有运行没有匹配就结束
List Comprehension 的主要目的是创建一个新的列表。因此,它只会在运行并准备新列表时停止。 in
运算符将遍历新生成的列表和 returns True
如果列表中的任何项目与正在搜索的实际项目匹配。例如,
>>> lc = [item * 2 for item in range(10)]
>>> lc
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> 4 in lc
True
在生成器表达式的情况下,in
运算符将调用生成器的 __iter__
方法,并且当 __iter__
调用返回的项与实际匹配时它会立即停止正在搜索的项目。你可以这样确认
>>> ge = (item * 2 for item in range(10))
>>> ge
<generator object <genexpr> at 0x7f498a85fd70>
>>> 4 in ge
True
>>> list(ge)
[6, 8, 10, 12, 14, 16, 18]
正如您在此处看到的,ge
只会迭代直到找到匹配项。 ge
对象在 4 in ge
检查后转换为列表时,给出生成器表达式生成的其余元素。
因此,生成器表达式在这种情况下更好。
在重构一段代码时,我注意到了这一点:
if product_id in [c["id"] for c in self.data.load_products()]:
# Do something
反过来,load_products()
执行 SQL 查询,并且对于每个产品:
- 执行一些相对 CPU 昂贵的操作和:
- 使用
yield
将产品一一return给来电者。
据我所知,列表理解和生成器表达式之间的区别在于,在列表理解的情况下,所有产品都将从数据库加载并处理,即使第一个产品是匹配的。
因此,如果我用这样的生成器表达式替换它:
# ↴ ↴
if product_id in (c["id"] for c in self.data.load_products()):
# Do something
它可以通过最终减少工作量来改进代码,即一旦找到匹配项,就不会从数据库加载下一个产品,也不会对其进行处理。
不过,我不太了解 Python 可以肯定。
我说得对吗? Python 是否会在找到匹配项后立即停止,或者两段代码会执行相同的操作并从数据库中加载每个产品?
列表理解总是运行结束并将所有结果保存在内存中。
生成器(表达式或非表达式)可以短路如果使用得当——例如if product_id in <some generator>
确实会在找到匹配项后立即停止,只有运行没有匹配就结束
List Comprehension 的主要目的是创建一个新的列表。因此,它只会在运行并准备新列表时停止。 in
运算符将遍历新生成的列表和 returns True
如果列表中的任何项目与正在搜索的实际项目匹配。例如,
>>> lc = [item * 2 for item in range(10)]
>>> lc
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> 4 in lc
True
在生成器表达式的情况下,in
运算符将调用生成器的 __iter__
方法,并且当 __iter__
调用返回的项与实际匹配时它会立即停止正在搜索的项目。你可以这样确认
>>> ge = (item * 2 for item in range(10))
>>> ge
<generator object <genexpr> at 0x7f498a85fd70>
>>> 4 in ge
True
>>> list(ge)
[6, 8, 10, 12, 14, 16, 18]
正如您在此处看到的,ge
只会迭代直到找到匹配项。 ge
对象在 4 in ge
检查后转换为列表时,给出生成器表达式生成的其余元素。
因此,生成器表达式在这种情况下更好。