發電機表達

生成器表示式與列表推導非常相似。主要區別在於它不會立即建立一整套結果; 它建立了一個生成器物件 ,然後可以迭代。

例如,請參閱以下程式碼中的差異:

# 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