發電機表達
生成器表示式與列表推導非常相似。主要區別在於它不會立即建立一整套結果; 它建立了一個生成器物件 ,然後可以迭代。
例如,請參閱以下程式碼中的差異:
# 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