发电机表达

生成器表达式与列表推导非常相似。主要区别在于它不会立即创建一整套结果; 它创建了一个生成器对象 ,然后可以迭代。

例如,请参阅以下代码中的差异:

# 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