发电机表达
生成器表达式与列表推导非常相似。主要区别在于它不会立即创建一整套结果; 它创建了一个生成器对象 ,然后可以迭代。
例如,请参阅以下代码中的差异:
# list comprehension
[x**2 for x in range(10)]
# Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Python 2.x >= 2.4
# generator comprehension
(x**2 for x in xrange(10))
# Output: <generator object <genexpr> at 0x11b4b7c80>
这是两个非常不同的对象:
-
list comprehension 返回
list
对象,而生成器理解返回generator
。 -
generator
对象无法编入索引,并使用next
函数按顺序获取项目。
注意 :我们使用 xrange
,因为它也创建了一个生成器对象。如果我们使用范围,将创建一个列表。此外,xrange
仅存在于 python 2 的更高版本中。在 python 3 中,range
只返回一个生成器。有关更多信息,请参阅范围和 xrange 函数示例之间 的差异 。
Python 2.x >= 2.4
g = (x**2 for x in xrange(10))
print(g[0])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'generator' object has no attribute '__getitem__'
g.next() # 0
g.next() # 1
g.next() # 4
...
g.next() # 81
g.next() # Throws StopIteration Exception
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Python 3.x >= 3.0
注意:函数
g.next()
应该由next(g)
和xrange
替换为range
,因为在 Python 3 中不存在Iterator.next()
和xrange()
。
虽然这两个都可以以类似的方式迭代:
for i in [x**2 for x in range(10)]:
print(i)
"""
Out:
0
1
4
...
81
"""
Python 2.x >= 2.4
for i in (x**2 for x in xrange(10)):
print(i)
"""
Out:
0
1
4
.
.
.
81
"""
用例
生成器表达式被延迟评估,这意味着它们仅在迭代生成器时生成并返回每个值。在迭代大型数据集时,这通常很有用,无需在内存中创建数据集的副本:
for square in (x**2 for x in range(1000000)):
#do something
另一个常见用例是,如果不需要,则避免迭代整个 iterable。在此示例中,每次迭代 get_objects()
都会从远程 API 检索项目。可能存在数千个对象,必须逐个检索,我们只需要知道是否存在与模式匹配的对象。通过使用生成器表达式,当我们遇到匹配模式的对象时。
def get_objects():
"""Gets objects from an API one by one"""
while True:
yield get_next_item()
def object_matches_pattern(obj):
# perform potentially complex calculation
return matches_pattern
def right_item_exists():
items = (object_matched_pattern(each) for each in get_objects())
for item in items:
if item.is_the_right_one:
return True
return False