Springboot的優點 內置servlet容器,不需要在伺服器部署 tomcat。只需要將項目打成 jar 包,使用 java -jar xxx.jar一鍵式啟動項目 SpringBoot提供了starter,把常用庫聚合在一起,簡化複雜的環境配置,快速搭建spring應用環境 可以快速創建獨立 ...
在 Python3 中,生成器表達式是一種語言結構,它可以快速地創建一個可迭代對象。生成器表達式類似於列表推導式,但使用圓括弧而不是方括弧,並且返回的是一個生成器對象而不是一個列表。
在 Python3 中,生成器表達式有兩種類型:生成器函數和生成器表達式。
- 生成器函數:
生成器函數是一種特殊的函數,在函數中使用 yield 語句來生成一個值,然後暫停函數執行並保留當前狀態,等待下一次調用時繼續執行。生成器函數的優點是可以處理大量數據,因為它們只需要在記憶體中保存一個值,而不是全部保存在記憶體中。
例如,以下是一個生成器函數,它可以生成斐波那契數列中的前 n 個數字:
def fibonacci(n): a, b = 0, 1 for i in range(n): yield a a, b = b, a + b
- 生成器表達式:
生成器表達式是使用圓括弧包圍的表達式,其中包含一個 for 迴圈和一個可選的 if 條件。生成器表達式可以用來生成一個序列,這個序列可以通過迭代訪問,但不必事先將所有元素保存在記憶體中。
例如,以下生成器表達式可以生成一個包含從 1 到 10 的偶數的生成器對象:
gen = (i for i in range(1, 11) if i % 2 == 0)
註意事項:
- 生成器表達式可以節省記憶體空間,但是如果需要多次使用生成器對象中的值,則需要將其轉換為列表或其他數據結構。
- 如果生成器表達式中的代碼太長或複雜,則建議使用生成器函數來代替,以提高代碼的可讀性和可維護性。
- 如果生成器表達式中的代碼有副作用(例如修改了全局變數),則可能會導致意外行為,應該避免這種情況。
- 生成器表達式可以嵌套,但是應該註意不要嵌套過深導致代碼難以理解。例如:
gen = ((i, j) for i in range(1, 4) for j in range(4, 7))
這個生成器表達式可以生成一個包含所有 (1,4) 到 (3,6) 的元組的生成器對象。
- 生成器表達式中的 for 迴圈可以有多個,每個迴圈可以使用一個 if 條件。例如:
gen = (i * j for i in range(1, 4) if i % 2 == 0 for j in range(4, 7) if j % 2 != 0)
這個生成器表達式可以生成一個包含所有偶數 i 與奇數 j 的乘積的生成器對象。
- 生成器表達式中的變數作用域只在生成器表達式內部,不會泄露到外部。例如:
x = 10 gen = (x for x in range(1, 5)) print(list(gen)) # 輸出 [1, 2, 3, 4] print(x) # 輸出 10,說明 x 只在生成器表達式內部存在,不會影響外部變數 x 的值。
- 生成器表達式可以和其他 Python 的內置函數或模塊一起使用,例如 map、filter、itertools 等。例如:
import itertools # 使用 map 函數和生成器表達式生成一個列表,其中每個元素都是平方數。 lst = list(map(lambda x: x ** 2, (i for i in range(1, 5)))) print(lst) # 輸出 [1, 4, 9, 16] # 使用 itertools 模塊中的 zip_longest 函數和生成器表達式生成一個包含所有輸入迭代器的元組的列表。 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)]
- 在使用生成器表達式時,應該儘可能地使用惰性求值,即只生成需要的元素,並且在使用完之後立即釋放相應的資源。這樣可以避免不必要的記憶體占用和性能問題。
- 處理大型數據集,例如從文件或資料庫中讀取數據,並將其用作生成器表達式的輸入。這樣可以避免一次性載入所有數據,並且節省記憶體空間。
with open('data.txt') as f: gen = (line.strip() for line in f if 'error' in line) for item in gen: print(item)
- 通過生成器表達式實現惰性求值,例如只有當需要時才計算函數的值。這樣可以避免不必要的計算和記憶體占用。
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]
這個例子中,我們定義了一個函數 expensive_function,並使用一個生成器表達式來生成一個包含前五個數字的平方的列表。在評估生成器表達式時,expensive_function 只有在需要計算平方時才被調用,這樣可以避免不必要的計算和記憶體占用。
- 在多個迭代器之間生成元素,例如合併兩個排序列表並返回一個新的排序列表。
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]
這個例子中,我們定義了一個 merge_sorted 函數來合併兩個排序列表,並返回一個新的排序列表。在函數中,我們使用一個生成器函數來生成所有排好序的元素,併在函數返回之前返回它們。這個方法可以在處理大型數據集時節省記憶體空間,並且可以避免不必要的排序或其他操作。
- 用於過濾和轉換數據,例如將一個列表中的所有元素轉換為字元串並刪除其中的空格。
lst = [' hello ', ' world', '', 'python', ''] gen = (s.strip() for s in lst if s) print(list(gen)) # 輸出 ['hello', 'world', 'python']
這個例子中,我們使用一個生成器表達式來對列表中的所有元素進行過濾和轉換。具體來說,我們首先使用 if 子句來過濾出所有不為空的字元串,然後使用 strip 方法來刪除每個字元串的前導和尾隨空格。最後,我們將經過處理的字元串返回為一個生成器對象,並將其轉換為一個列表。
-
生成器表達式可以與其他 Python 內置函數(如 map 和 filter)和模塊(如 itertools)結合使用,以實現更高效和優雅的代碼。
-
在使用生成器表達式時,應該儘可能地使用惰性求值,即只生成需要的元素,併在使用完之後立即釋放相應的資源。這樣可以避免不必要的記憶體占用和性能問題。
-
如果生成器表達式中的代碼有副作用(例如修改了全局變數),則可能會導致意外行為,應該避免這種情況。
-
在編寫長的生成器表達式時,建議將其分解成多個簡單的表達式或生成器函數,以提高代碼的可讀性和可維護性。
-
在使用生成器表達式時,應該學會使用列表推導式和普通的 for 迴圈來進行比較,以選擇最適合特定任務的工具。
-
最後,需要註意的是,生成器表達式雖然非常強大和方便,但也並非萬能的。在某些情況下,還是需要使用其他語言結構或演算法來解決問題。
-
在使用生成器表達式時,應該避免使用過多的嵌套迴圈和條件語句,以免代碼變得難以閱讀和維護。在這種情況下,建議考慮使用其他數據結構或演算法。
-
使用生成器表達式時,應該儘可能地保持代碼簡單和易讀。這包括命名變數、註釋代碼和格式化輸出,以便其他人可以理解你的代碼。
-
在使用生成器表達式時,需要註意一些性能問題。例如,在處理大型數據集時,可能需要考慮使用並行計算或其他優化演算法來提高效率。讓我們來看一個例子,說明生成器表達式和列表推導式之間的差異:
讓我們來看一個例子,說明生成器表達式和列表推導式之間的差異:
# 列表推導式 lst = [i ** 2 for i in range(1, 11)] print(lst) # 生成器表達式 gen = (i ** 2 for i in range(1, 11)) print(list(gen))
個例子中,我們首先使用列表推導式創建一個包含前 10 個數字的平方的列表。然後,我們使用一個生成器表達式來創建一個包含相同元素的生成器對象,並將其轉換為一個列表。
一般來說,列表推導式比起生成器表達式更加適合小型數據集,因為它們可以在記憶體中完全構建出一個列表,並且可以在需要時隨時進行索引和修改。另一方面,生成器表達式更適合大型數據集,因為它們只返回必要的元素,而且可以逐個處理每個元素,從而節省記憶體空間。
在實際編程中,我們應該根據具體情況選擇最適合的工具,並權衡各種因素(例如代碼的可讀性、效率、記憶體占用等)。