在 Python3 中,生成器表達(dá)式是一種語言結(jié)構(gòu),它可以快速地創(chuàng)建一個(gè)可迭代對(duì)象。生成器表達(dá)式類似于列表推導(dǎo)式,但使用圓括號(hào)而不是方括號(hào),并且返回的是一個(gè)生成器對(duì)象而不是一個(gè)列表。
在 Python3 中,生成器表達(dá)式有兩種類型:生成器函數(shù)和生成器表達(dá)式。
- 生成器函數(shù):
生成器函數(shù)是一種特殊的函數(shù),在函數(shù)中使用 yield 語句來生成一個(gè)值,然后暫停函數(shù)執(zhí)行并保留當(dāng)前狀態(tài),等待下一次調(diào)用時(shí)繼續(xù)執(zhí)行。生成器函數(shù)的優(yōu)點(diǎn)是可以處理大量數(shù)據(jù),因?yàn)樗鼈冎恍枰趦?nèi)存中保存一個(gè)值,而不是全部保存在內(nèi)存中。
例如,以下是一個(gè)生成器函數(shù),它可以生成斐波那契數(shù)列中的前 n 個(gè)數(shù)字:
def fibonacci(n): a, b = 0, 1 for i in range(n): yield a a, b = b, a + b
xx=fibonacci(9)
print(xx)
- 生成器表達(dá)式:
生成器表達(dá)式是使用圓括號(hào)包圍的表達(dá)式,其中包含一個(gè) for 循環(huán)和一個(gè)可選的 if 條件。生成器表達(dá)式可以用來生成一個(gè)序列,這個(gè)序列可以通過迭代訪問,但不必事先將所有元素保存在內(nèi)存中。
例如,以下生成器表達(dá)式可以生成一個(gè)包含從 1 到 10 的偶數(shù)的生成器對(duì)象:
gen = (i for i in range(1, 11) if i % 2 == 0)
注意事項(xiàng):
- 生成器表達(dá)式可以節(jié)省內(nèi)存空間,但是如果需要多次使用生成器對(duì)象中的值,則需要將其轉(zhuǎn)換為列表或其他數(shù)據(jù)結(jié)構(gòu)。
- 如果生成器表達(dá)式中的代碼太長(zhǎng)或復(fù)雜,則建議使用生成器函數(shù)來代替,以提高代碼的可讀性和可維護(hù)性。
- 如果生成器表達(dá)式中的代碼有副作用(例如修改了全局變量),則可能會(huì)導(dǎo)致意外行為,應(yīng)該避免這種情況。
- 生成器表達(dá)式可以嵌套,但是應(yīng)該注意不要嵌套過深導(dǎo)致代碼難以理解。例如:
gen = ((i, j) for i in range(1, 4) for j in range(4, 7))
這個(gè)生成器表達(dá)式可以生成一個(gè)包含所有 (1,4) 到 (3,6) 的元組的生成器對(duì)象。
- 生成器表達(dá)式中的 for 循環(huán)可以有多個(gè),每個(gè)循環(huán)可以使用一個(gè) if 條件。例如:
gen = (i * j for i in range(1, 4) if i % 2 == 0 for j in range(4, 7) if j % 2 != 0)
這個(gè)生成器表達(dá)式可以生成一個(gè)包含所有偶數(shù) i 與奇數(shù) j 的乘積的生成器對(duì)象。
- 生成器表達(dá)式中的變量作用域只在生成器表達(dá)式內(nèi)部,不會(huì)泄露到外部。例如:
x = 10 gen = (x for x in range(1, 5)) print(list(gen)) # 輸出 [1, 2, 3, 4] print(x) # 輸出 10,說明 x 只在生成器表達(dá)式內(nèi)部存在,不會(huì)影響外部變量 x 的值。
- 生成器表達(dá)式可以和其他 Python 的內(nèi)置函數(shù)或模塊一起使用,例如 map、filter、itertools 等。例如:
import itertools # 使用 map 函數(shù)和生成器表達(dá)式生成一個(gè)列表,其中每個(gè)元素都是平方數(shù)。 lst = list(map(lambda x: x ** 2, (i for i in range(1, 5)))) print(lst) # 輸出 [1, 4, 9, 16] # 使用 itertools 模塊中的 zip_longest 函數(shù)和生成器表達(dá)式生成一個(gè)包含所有輸入迭代器的元組的列表。 lst = list(itertools.zip_longest((i for i in range(1, 5)), ('a', 'b', 'c'))) print(lst) # 輸出 [(1, 'a'), (2, 'b'), (3, 'c'), (4, None)]
- 在使用生成器表達(dá)式時(shí),應(yīng)該盡可能地使用惰性求值,即只生成需要的元素,并且在使用完之后立即釋放相應(yīng)的資源。這樣可以避免不必要的內(nèi)存占用和性能問題。
- 處理大型數(shù)據(jù)集,例如從文件或數(shù)據(jù)庫(kù)中讀取數(shù)據(jù),并將其用作生成器表達(dá)式的輸入。這樣可以避免一次性加載所有數(shù)據(jù),并且節(jié)省內(nèi)存空間。
with open('data.txt') as f: gen = (line.strip() for line in f if 'error' in line) for item in gen: print(item)
- 通過生成器表達(dá)式實(shí)現(xiàn)惰性求值,例如只有當(dāng)需要時(shí)才計(jì)算函數(shù)的值。這樣可以避免不必要的計(jì)算和內(nèi)存占用。
def expensive_function(n): print(f"Calculating {n}...") return n ** 2 gen = (expensive_function(i) for i in range(5)) print(list(gen)) # 輸出 Calculating 0... Calculating 1... Calculating 2... Calculating 3... Calculating 4... [0, 1, 4, 9, 16]
這個(gè)例子中,我們定義了一個(gè)函數(shù) expensive_function,并使用一個(gè)生成器表達(dá)式來生成一個(gè)包含前五個(gè)數(shù)字的平方的列表。在評(píng)估生成器表達(dá)式時(shí),expensive_function 只有在需要計(jì)算平方時(shí)才被調(diào)用,這樣可以避免不必要的計(jì)算和內(nèi)存占用。
- 在多個(gè)迭代器之間生成元素,例如合并兩個(gè)排序列表并返回一個(gè)新的排序列表。
def merge_sorted(lst1, lst2): i, j = 0, 0 while i < len(lst1) and j < len(lst2): if lst1[i] <= lst2[j]: yield lst1[i] i += 1 else: yield lst2[j] j += 1 yield from lst1[i:] yield from lst2[j:] lst1 = [1, 3, 5, 7] lst2 = [2, 4, 6, 8] gen = merge_sorted(lst1, lst2) print(list(gen)) # 輸出 [1, 2, 3, 4, 5, 6, 7, 8]
這個(gè)例子中,我們定義了一個(gè) merge_sorted 函數(shù)來合并兩個(gè)排序列表,并返回一個(gè)新的排序列表。在函數(shù)中,我們使用一個(gè)生成器函數(shù)來生成所有排好序的元素,并在函數(shù)返回之前返回它們。這個(gè)方法可以在處理大型數(shù)據(jù)集時(shí)節(jié)省內(nèi)存空間,并且可以避免不必要的排序或其他操作。
- 用于過濾和轉(zhuǎn)換數(shù)據(jù),例如將一個(gè)列表中的所有元素轉(zhuǎn)換為字符串并刪除其中的空格。
lst = [' hello ', ' world', '', 'python', ''] gen = (s.strip() for s in lst if s) print(list(gen)) # 輸出 ['hello', 'world', 'python']
這個(gè)例子中,我們使用一個(gè)生成器表達(dá)式來對(duì)列表中的所有元素進(jìn)行過濾和轉(zhuǎn)換。具體來說,我們首先使用 if 子句來過濾出所有不為空的字符串,然后使用 strip 方法來刪除每個(gè)字符串的前導(dǎo)和尾隨空格。最后,我們將經(jīng)過處理的字符串返回為一個(gè)生成器對(duì)象,并將其轉(zhuǎn)換為一個(gè)列表。
-
生成器表達(dá)式可以與其他 Python 內(nèi)置函數(shù)(如 map 和 filter)和模塊(如 itertools)結(jié)合使用,以實(shí)現(xiàn)更高效和優(yōu)雅的代碼。
-
在使用生成器表達(dá)式時(shí),應(yīng)該盡可能地使用惰性求值,即只生成需要的元素,并在使用完之后立即釋放相應(yīng)的資源。這樣可以避免不必要的內(nèi)存占用和性能問題。
-
如果生成器表達(dá)式中的代碼有副作用(例如修改了全局變量),則可能會(huì)導(dǎo)致意外行為,應(yīng)該避免這種情況。
-
在編寫長(zhǎng)的生成器表達(dá)式時(shí),建議將其分解成多個(gè)簡(jiǎn)單的表達(dá)式或生成器函數(shù),以提高代碼的可讀性和可維護(hù)性。
-
在使用生成器表達(dá)式時(shí),應(yīng)該學(xué)會(huì)使用列表推導(dǎo)式和普通的 for 循環(huán)來進(jìn)行比較,以選擇最適合特定任務(wù)的工具。
-
最后,需要注意的是,生成器表達(dá)式雖然非常強(qiáng)大和方便,但也并非萬能的。在某些情況下,還是需要使用其他語言結(jié)構(gòu)或算法來解決問題。
-
在使用生成器表達(dá)式時(shí),應(yīng)該避免使用過多的嵌套循環(huán)和條件語句,以免代碼變得難以閱讀和維護(hù)。在這種情況下,建議考慮使用其他數(shù)據(jù)結(jié)構(gòu)或算法。
-
使用生成器表達(dá)式時(shí),應(yīng)該盡可能地保持代碼簡(jiǎn)單和易讀。這包括命名變量、注釋代碼和格式化輸出,以便其他人可以理解你的代碼。
-
在使用生成器表達(dá)式時(shí),需要注意一些性能問題。例如,在處理大型數(shù)據(jù)集時(shí),可能需要考慮使用并行計(jì)算或其他優(yōu)化算法來提高效率。讓我們來看一個(gè)例子,說明生成器表達(dá)式和列表推導(dǎo)式之間的差異:
讓我們來看一個(gè)例子,說明生成器表達(dá)式和列表推導(dǎo)式之間的差異:
# 列表推導(dǎo)式 lst = [i ** 2 for i in range(1, 11)] print(lst) # 生成器表達(dá)式 gen = (i ** 2 for i in range(1, 11)) print(list(gen))
個(gè)例子中,我們首先使用列表推導(dǎo)式創(chuàng)建一個(gè)包含前 10 個(gè)數(shù)字的平方的列表。然后,我們使用一個(gè)生成器表達(dá)式來創(chuàng)建一個(gè)包含相同元素的生成器對(duì)象,并將其轉(zhuǎn)換為一個(gè)列表。
一般來說,列表推導(dǎo)式比起生成器表達(dá)式更加適合小型數(shù)據(jù)集,因?yàn)樗鼈兛梢栽趦?nèi)存中完全構(gòu)建出一個(gè)列表,并且可以在需要時(shí)隨時(shí)進(jìn)行索引和修改。另一方面,生成器表達(dá)式更適合大型數(shù)據(jù)集,因?yàn)樗鼈冎环祷乇匾脑?,而且可以逐個(gè)處理每個(gè)元素,從而節(jié)省內(nèi)存空間。
Python標(biāo)準(zhǔn)庫(kù)還提供了許多內(nèi)置函數(shù)和模塊,可以幫助我們更加方便地處理和操作生成器。
其中一個(gè)比較常見的內(nèi)置函數(shù)是next()
函數(shù)。它用于從生成器中獲取下一個(gè)值,并將生成器的執(zhí)行狀態(tài)從上一次掛起的位置繼續(xù)向下執(zhí)行。
以下是一個(gè)使用next()函數(shù)打印斐波那契數(shù)列的示例:
def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b # 輸出前10項(xiàng)斐波那契數(shù)列 fib = fibonacci() for i in range(10): print(next(fib))
在這個(gè)示例中,使用一個(gè)無限循環(huán)的生成器函數(shù)來計(jì)算斐波那契數(shù)列。然后,通過調(diào)用next()函數(shù)逐一輸出數(shù)列的前10項(xiàng)。每次調(diào)用next()函數(shù)時(shí),生成器函數(shù)會(huì)從上一次yield語句掛起的位置繼續(xù)執(zhí)行,直到下一個(gè)yield語句為止。
除了next()函數(shù)之外,Python標(biāo)準(zhǔn)庫(kù)還提供了一些其他有用的生成器相關(guān)函數(shù)和模塊,例如:
-
itertools
: 一個(gè)集合了許多有用的迭代器函數(shù)的模塊,如排列、組合、笛卡爾積等。 -
enumerate()
: 返回一個(gè)由索引和元素組成的迭代器對(duì)象,常用于遍歷序列時(shí)獲取元素的索引。 -
filter()
: 返回一個(gè)由滿足某個(gè)條件的元素組成的迭代器對(duì)象,常用于過濾序列中的元素。 -
map()
: 對(duì)序列中的每個(gè)元素應(yīng)用一個(gè)函數(shù),并返回一個(gè)由處理結(jié)果組成的迭代器對(duì)象。 -
zip()
: 將多個(gè)序列打包為一個(gè)元組構(gòu)成的迭代器對(duì)象,常用于將多個(gè)列表或元組同時(shí)遍歷。
這些函數(shù)和模塊可以幫助我們更加方便地使用生成器,并讓我們的代碼變得更加簡(jiǎn)潔和高效。文章來源:http://www.zghlxwxcb.cn/news/detail-433324.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-433324.html
到了這里,關(guān)于python3 生成器與生成器表達(dá)式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!