生成式整理

  • 串列生成式:[運算式 for 項目 in 可迭代項目]
  • 字典生成式:{鍵運算式:值運算式 for 運算式 in 可迭代項目}
  • 集合生成式:{運算式 for 運算式 in 可迭代項目}
  • 產生器生成式:
  • tuple 沒有生成式

生成式

  • 生成式是一種以一或多個迭代器,來密集建立 Python 資料結構的方式
  • 藉由生成式,可以結合迴圈與條件測試式,以減少繁瑣的語法

串列生成式

有效的 Python 程式,產生與串列生成式相同的結果

【方法一】建立串列,一次建立一個項目

建立一個從整數 1 到 5 的串列,一次建立一個項目

>>> 變數 = []
>>> 變數.append(數字1)
>>> 變數.append(數字2)
>>> 變數.append(數字3)
>>> 變數.append(數字4)
>>> 變數.append(數字5)
>>> 變數
[數字1, 數字2, 數字3, 數字4, 數字5]
>>> number_list = []
>>> number_list.append(1)
>>> number_list.append(2)
>>> number_list.append(3)
>>> number_list.append(4)
>>> number_list.append(5)
>>> number_list
[1, 2, 3, 4, 5]

【方法二】一個迭代器與 range()函式

>>> 變數1 = []
>>> for 變數2 in range(數字1, 數字6):
        變數1.append(變數2)

>>> 變數1
[數字1, 數字2, 數字3, 數字4, 數字5]
>>> number_list = []
>>> for number in range(1, 6):
    number_list.append(number)

>>> number_list
[1, 2, 3, 4, 5]

【方法三】將 range() 的輸出轉成串列

>>> 變數 = list(range(變數1, 變數6))
>>> 變數
[變數1, 變數2, 變數3, 變數4, 變數5]
>>> number_list = list(range(1, 6))
>>> number_list
[1, 2, 3, 4, 5]

串列生成式

  • 以上所有方法都是有效的 Python 程式,也都會產生與串列生成式相同的結果
  • 要建立串列較符合 Python 風格的方式,就是使用串列生成式
  • 以下是最簡單的串列生成式的形式:

[運算式 for 項目 in 可迭代項目]

【範例一】「串列生成式」建構「整數串列」的方式

>>> 變數1 = [變數2 for 變數2 in range(數字1, 數字6)]
>>> 變數1
[數字1, 數字2, 數字3, 數字4, 數字5]
>>> number_list = [number for number in range(1, 6)]
>>> number_list
[1, 2, 3, 4, 5]

【範例二】[運算式 for 項目 in 可迭代項目]

  • 變數 = [number-1 for number in range(數字1, 數字2)]
  • 為了說明第一個 number 是個運算式,請改用這種方式
>>> 變數1 = [變數2-1 for 變數2 in range(數字1, 數字6)]
>>> 變數1
[數字0, 數字1, 數字2, 數字3, 數字4]
>>> number_list = [number-1 for number in range(1, 6)]
>>> number_list
[0, 1, 2, 3, 4]

串列生成式 + 條件運算式(迴圈)

  • 這個串列生成式將「迴圈」放入方括號內。串列生成式可以容納條件運算式

[運算式 for 項目 in 可迭代項目 if 條件式]

【方法一】利用生成式,建立奇數串列

  1. 製作一個新的生成式
  2. 用它來建立一個裡面只有 1 到 5 的奇數串列
  3. number % 2 是 True 代表它是奇數,False 是偶數
>>> 變數1 = [變數2 for 變數2 in range(數字1,數字6) if 變數2 % 2 == 1]
>>> 變數1
[數字1, 數字3, 數字5]
>>> a_list = [number for number in range(1, 6) if number % 2 == 1]
>>> a_list
[1, 3, 5]

【方法二】利用生成式,建立奇數串列

>>> 變數1 = []
>>> for 變數2 in range(數字1, 數字6):
        if 變數2 % 2 == 1:
        變數1.append(變數2)

>>> 變數1
[數字1, 數字3, 數字5]
>>> a_list = []
>>> for number in range(1, 6):
    if number % 2 == 1:
        a_list.append(number)

>>> a_list
[1, 3, 5]

嵌套的迴圈(使用二組以上的 for...子句)

【方法一】一般、舊式的嵌套迴圈

  1. 使用嵌套的迴圈,也可以在對應的生成式中,使用二組以上的 for ... 子句
  2. 為了說明這一點,先嘗試一般、舊式的嵌套迴圈,並印出結果
>>> 變數1s = range(數字1, 數字4)
>>> 變數2s = range(數字1, 數字3)
>>> for 變數1 in 變數1s:
        for 變數2 in 變數2s:
            print(變數1, 變數2)
>> rows = range(1, 4)
>>> cols = range(1, 3)
>>> for row in rows:
    for col in cols:
        print(row, col)


1 1
1 2
2 1
2 2
3 1
3 2

【方法二】使用生成式,指派給變數,製作一串 Tuple

>>> 變數1s = range(數字1, 數字4)
>>> 變數2s = range(數字1, 數字3)
>>> 變數3s = [(變數1, 變數2) for 變數1 in 變數1s for 變數2 in 變數2s]
>>> for 變數3 in 變數3s:
        print(變數3)
  • 使用生成式,並將它指派給變數 cells,製作一串(row, col)tuple
>>> rows = range(1, 4)
>>> cols = range(1, 3)
>>> cells = [(row, col) for row in rows for col in cols]
>>> for cell in cells:
    print(cell)

(1, 1)
(1, 2)
(2, 1)
(2, 2)
(3, 1)
(3, 2)

【方法三】迭代串列時,使用 tuple unpacking,從每一個 tuple 中拉出值

>>> 變數1s = range(數字1, 數字4)
>>> 變數2s = range(數字1, 數字3)
>>> for 變數1, 變數2 in 變數3s:
        print(變數1, 變數2)
  1. 使用生成式,並將它指派給變數 cells,製作一串(row, col)tuple
  2. 迭代 cells 串列時,也可以使用 tuple unpacking,從每一個 tuple 中拉出 row 與 col 值
  3. 串列生成式中的 row... 與 for col ... 段落,也可以擁有它們自己的 if 測試值
>>> rows = range(1, 4)
>>> cols = range(1, 3)
>>> for row, col in cells:
    print(row, col)

1 1
1 2
2 1
2 2
3 1
3 2

字典生成式

  • 與串列生成式很像,字典生成式也可以用 if 測試式與多個 for 子句
  • 字典生成式的形式

    {鍵運算式:值運算式 for 運算式 in 可迭代項目}

字典生成式 + if 測試式 + 多個 for 子句

>>> 變數1 = '字元1字元2字元3字元4'
>>> 變數2 = {變數3: 變數4.count(變數3) for 變數3 in 變數4}
>>> 變數2
{'字元1':1, '字元2':1, '字元3':1, '字元4':1}
>>> word = 'letters'
>>> letter_counts = {letter: word.count(letter) for letter in word}
>>> letter_counts
{'l': 1, 'e': 2, 't': 2, 'r': 1, 's': 1}
  1. 對字串 'letters' 的七個字母分別執行迴圈,並計算該字母出現的次數
  2. 使用兩次 word.count(letter) 是浪費時間的做法,因為這樣必須計算 e 兩次、t 三次
  3. 當第二次計算 e 時,不會造成任何影響,因為只是更換字典內既有的項目,t 也一樣
  4. 所以,下列程式比較像 Python 的風格
  5. 這個字典的鍵的順序與之前的範例不同,因為迭代 set(word) 時,它回傳字母的順序與迭代 word 字串不同
>>> 變數1 = '字元1字元2字元3字元4'
>>> 變數2 = {變數3: 變數1.count(變數3) for 變數3 in set(變數1)}
>>> 變數2
{'字元1': 1, '字元2': 1, '字元3': 1, '字元4': 1}
>>> word = 'letters'
>>> letter_counts = {letter: word.count(letter) for letter in set(word)}
>>> letter_counts
{'s': 1, 'r': 1, 't': 2, 'e': 2, 'l': 1}

集合生成式

集合生成式的形式

{ 運算式 for 運算式 in 可迭代項目 }

加上「if 測試式,多個 for 子句」也是有效

>>> 變數1 = {變數2 for 變數2 in range(數字1, 數字6) if 變數2 % 3 == 1}
>>> 變數1
{數字1, 數字4}

產生器生成式

  • tuple 沒有生成式!
  • 產生器是一種將資料提供給迭代器的方式

產生器生成式 → 回傳產生器物件

  • 在括號之間的東西,是產生器生成式 → 回傳產生器物件
    1. 或許你認為:串列生成式的方括號[],就可以改成括號(),就可以做成 tuple 生成式
    2. 輸入下列程式的話,它並不會產生例外,所以看起來像是有效的
    3. 在括號之間的東西,是產生器生成式 → 回傳產生器物件
>>> number_thing = (number for number in range(1, 6))
>>> type(number_thing)
<class 'generator'>

可以直接迭代產生器物件

>>> for number in number_thing:
    print(number)

1
2
3
4
5

「產生器生成式」包裝成一個「list()呼叫式」→ 動作就像「串列生成式」

>>> 串列生成式 = list(產生器生成式)
>>> 串列生成式
>>> number_thing = (number for number in range(1, 6))
>>> number_list = list(number_thing)
>>> number_list
[1, 2, 3, 4, 5]

產生器只能執行一次

  • 產生器只能執行一次
  • 串列、集合、字串與字典都會被放在記憶體裡面,但產生器會動態產生它的值,並透過「迭代器」,一次送出一個值
  • 它不會記得那些值,所以你無法啟動或備份產生器

如果試著重新迭代產生器,會看到它跳出

>>> try_again = list(number_thing)
>>> try_again
[]

產生器函式

  • 用「產生器生成式」,或用「產生器函式」 → 來建立一個「產生器」
  • 我們會大略討論函式,再進行產生器函式

results matching ""

    No results matching ""