Python 標準程式庫

接下來的章節會討論 Web、系統、資料庫等專用的標準模組。這一節,會討論一些標準的通用模組。

處理遺漏的鍵【使用 setdefault() 與 defaultdict()】

  • 不存在的鍵存取字典 → 產生例外
  • 字典 get() 函式 → 回傳一個預設值,避免例外發生
  • setdefault()函式 → 就像 get(),但是如果鍵遺漏的話,也會指派一個項目給字典

setdefault()

鍵沒有在字典裡面 → 使用新值

>>> 字典名稱 = {'鍵1': 值1, '鍵2': 值2}
>>> print(字典名稱)
{'鍵1': 值1, '鍵2': 值2}

>>> 變數1 = 字典名稱.setdefault('鍵3': 值3)
>>> 變數1                                   # 鍵沒有在字典裡面 → 使用新值3
>>> 字典名稱
{'鍵1': 值1, '鍵2': 值2, '鍵3': 值3}
>>> periodic_table = {'Hydrogen': 1, 'Helium': 2}
>>> print(periodic_table)
{'Hydrogen': 1, 'Helium': 2}

>>> carbon = periodic_table.setdefault('Carbon', 12)
>>> carbon
12
>>> periodic_table
{'Hydrogen': 1, 'Helium': 2, 'Carbon': 12}

指派「不同的預設值」給「一個已經存在的鍵」 → 回傳原始值,不會改變任何東西

>>> 變數2 = 字典名稱.setdefault('鍵2': 值4)                 # 指派「不同的預設值」給「一個已經存在的鍵」
>>> 變數22                                                       # 回傳原始值,不會改變任何東西
>>> 字典名稱
{'鍵1': 值1, '鍵2': 值2, '鍵3': 值3}
>>> helium = periodic_table.setdefault('Helium', 947)     # 指派「不同的預設值」給「一個已經存在的鍵」
>>> helium
2                                                         # 回傳原始值,不會改變任何東西
>>> periodic_table
{'Hydrogen': 1, 'Helium': 2, 'Carbon': 12}

defaultdict()

字典被建立時,為任何新鍵指定預設值(它的引數是個函式)

【範例】傳遞函式 → 當它被呼叫時,會使用 int() → 回傳整數0

# 傳遞函式 → 當它被呼叫時,會使用 int() → 回傳整數0
>>> from collections import defaultdict
>>> 字典名稱 = defaultdict(int)

# 現在,任何遺漏的值都會是一個整數(int),其值為0
>>> 字典名稱['鍵1'] = 值1
>>> 字典名稱['鍵5']                                         # 任何遺漏的值都會是一個整數(int),其值為0
0
>>> 字典名稱
defaultdict(<class 'int'>, {'鍵1': '值1', '鍵5': 0})
>>> from collections import defaultdict                    # defaultdict()很類似,但它會在字典被建立時,「為任何新鍵指定預設值」
>>> periodic_table = defaultdict(int)                      # defaultdict(),它的引數是個函式

# 傳遞函式 int,當它被呼叫時,會使用 int(),並回傳整數 0
>>> periodic_table['Hydrogen'] = 1
>>> periodic_table['Lead']                                 # 現在,任何遺漏的值都會是一個整數(int),其值為0
0
>>> periodic_table
defaultdict(<class 'int'>, {'Hydrogen': 1, 'Lead': 0})

被傳入 defaultdict() 的引數是「一個函式」→ 回傳將要被指派給「遺漏的鍵的值」

【範例】必要時,執行 no_idea() → 以回傳一個值

>>> from collections import defaultdict
>>> def no_idea():
        return '文字?'                        # 回傳將要被指派給「遺漏的鍵的值」

>>> 變數3 = defaultdict(no_idea)              # 被傳入 defaultdict() 的引數是「一個函式」
>>> 變數3['鍵6'] = '值6'
>>> 變數3['鍵7'] = '值7'
>>> 變數3['鍵6']
'值6'
>>> 變數3['鍵7']
'值7'
>>> 變數3['鍵8']                              # 回傳「遺漏的鍵的值」
'文字'
>>> from collections import defaultdict
>>> def no_idea():
    return 'Huh?'

>>> bestiary = defaultdict(no_idea)          # 被傳入 defaultdict() 的引數是「一個函式」→ 回傳將要被指派給「遺漏的鍵的值」
>>> bestiary['A'] = 'Abominable Snowman'
>>> bestiary['B'] = 'Basilisk'
>>> bestiary['A']
'Abominable Snowman'
>>> bestiary['B']
'Basilisk'
>>> bestiary['C']                            # 必要時,執行 no_idea() → 以回傳一個值
'Huh?'

使用函式 int()、list() 或 dict() → 回傳這些類型的「預設空白值」

  • int() → 回傳 0
  • list() → 回傳 空串列([])
  • dict() → 回傳 空字典({})
  • 省略引數 → 「新鍵的初始值」會被設為「None」

使用 lambda → 在呼叫式中「定義預設的函式」

>>> 變數3 = defaultdict(lambda: '文字')
>>> 變數3['鍵9']
'文字'
>>> bestiary = defaultdict(lambda: 'Huh?')     # 使用 lambda → 在呼叫式中「定義預設的函式」
>>> bestiary['E']
'Huh?'

製作計數器【使用int, for...in 】

>>> from collections import defaultdict
>>> 變數4 = defaultdict(int)
>>> for 引數1 in ['字串1', '字串1', '字串2', '字串1']:
        變數4[引數1] += 1

>>> for 引數1, 引數2 in 變數4.items():
        print(引數1, 引數2)

字串2 1
字串1 3
>> from collections import defaultdict
>>> food_counter = defaultdict(int)
>>> for food in ['spam', 'spam', 'eggs', 'spam']:
    food_counter[food] += 1

>>> for food, count in food_counter.items():
    print(food, count)

spam 3
eggs 1

一般字典,而不是 defaultdict,遞增字典元素 → 發出例外(因為尚未被初始化)

>>> 字典名稱 = {}
>>> for 引數1 in ['字串1', '字串1', '字串2', '字串1']:
        if not 引數 in 字典名稱:
            字典名稱[引數] = 0
        字典名稱[引數] += 1

>>> for 引數1, 引數2 in 字典名稱.items():
        print(引數1, 引數2)

字串1 3
字串2 1
# 如果 food_counter 是一個一般的字典,而不是 defaultdict
# 每當試著遞增字典元素 food_counter[food]時,Python 都會發出例外,因為它尚未被初始化
# 必須額外做些事情,如下所示

>>> dict_counter = {}
>>> for food in ['spam', 'spam', 'eggs', 'spam']:
    if not food in dict_counter:
        dict_counter[food] = 0
    dict_counter[food] += 1

>>> for food, count in dict_counter.items():
    print(food, count)

spam 3
eggs 1

計算項目數量【使用 counter()】

標準程式庫有一個計數器(除了之前的工作之外,它也能做其他的工作)

>>> from collections import Counter
>>> 串列名稱1 = ['字串1', '字串1', '字串2', '字串1']
>>> 串列名稱1_counter = Counter(串列名稱)
>>> 串列名稱1_counter
Counter({'字串1':3, '字串3': 1})
>>> from collections import Counter
>>> breakfast = ['spam', 'spam', 'eggs', 'spam']
>>> breakfast_counter = Counter(breakfast)
>>> breakfast_counter
Counter({'spam': 3, 'eggs': 1})

降冪回傳所有元素,或當指定一個數量時,回傳最前面的 count 個元素【使用 most_common()】

>>> 串列名稱1_counter.most_common()
[('字串1', 3), ('字串2', 1)]

>>> 串列名稱1_counter.most_common(1)
[('字串1', 3)]
>>> breakfast_counter.most_common()
[('spam', 3), ('eggs', 1)]
>>> breakfast_counter.most_common(1)
[('spam', 3)]

結合計數器使用

>>> 串列名稱1.counter
>>> Counter({'字串1': 3, '字串2': 1})
>>> breakfast_counter
Counter({'spam': 3, 'eggs': 1})

製作一個新的串列 + 一個計數器

>>> 串列名稱2 = ['字串2', '字串2', '字串3']
>>> 串列名稱2_counter = Counter(串列名稱)
>>> 串列名稱2_counter
Counter({'字串2': 2, '字串3': 1})
>>> lunch = ['eggs', 'eggs', 'bacon']
>>> lunch_counter = Counter(lunch)
>>> lunch_counter
Counter({'eggs': 2, 'bacon': 1})

結合兩個計數器【使用加法 +】

>>> 串列名稱1_counter + 串列名稱2_counter
Counter({'字串1': 3, '字串2': 3, '字串3': 1})
>>> breakfast_counter + lunch_counter
Counter({'spam': 3, 'eggs': 3, 'bacon': 1})

將另一個計數器減去另一個【使用 -】

【範例一】什麼食物早餐有,中餐沒有?

>>> 串列名稱1_counter - 串列名稱2_counter
Counter({'字串1': 3})
>>> breakfast_counter - lunch_counter
Counter({'spam': 3})

【範例二】什麼食物午餐有,早餐沒有?

>>> 串列名稱2_counter - 串列名稱1_counter
Counter({'字串2': 1, '字串3': 1})
>>> lunch_counter - breakfast_counter
Counter({'eggs': 1, 'bacon': 1})

使用交集運算子 & 來取得共同的項目

交集會選出數量較少的共同元素

>>> 串列名稱1_counter & 串列名稱2_counter      # 交集會選出數量較少的共同元素
Counter({'字串2': 1})
>>> breakfast_counter & lunch_counter
Counter({'eggs': 1})

聯集運算子 | 來取得所有項目

兩邊都有的項目,與加法不同的是,聯集不會加總它們的數量,而是選取數量較多的那一個項目

>>> 串列名稱1_counter | 串列名稱2_counter
Counter({'字串1': 3, '字串2': 2, '字串3': 1})
>>> breakfast_counter | lunch_counter
Counter({'spam': 3, 'eggs': 2, 'bacon': 1})

排序【使用鍵與 OrderedDict()】

  • 之前許多範例程式都說明,在字典中的「鍵的順序是無法預測的」→ 可能按照 a、b、c 的順序加入鍵,但 keys() 可能會回傳 c、a、b
>>> 字典名稱 = {
    '鍵1': '值1',
    '鍵2': '值2',
    '鍵3': '值3',
}

>>> for stooge in 字典名稱:
        print(stooge)

鍵231


會記得加入鍵的順序,並以「迭代器」按照同樣的順序回傳它們【使用 OrderedDict()】

【範例】用一系列的 (鍵, 值) tuple 來建立一個 OrderedDict

>>> from collections import OrderedDict
>>> tuple名稱 = OrderedDict([
        ('鍵1', '值1'),
        ('鍵2', '值2'),
        ('鍵3', '值3'),
        ])

>>> for stooge in tuple名稱:
        print(stooge)

鍵123
>>> quotes = {
    'Moe': 'A wise guy, huh?',
    'Larry': 'Ow!',
    'Curly': 'Nyuk nyuk!',
    }
>>> for stooge in quotes:
    print(stooge)

Moe
Larry
Curly

堆疊 + 序列 == deque

  • deque(唸成 deck),是一種雙頭的序列 → 它同時具有堆疊與序列的功能
  • 目標:
    • 想要從序列的任何一端「加入」或「刪除項目」時
    • 從一個單字的兩端檢查到它的中間 → 看看是否是個回文(palindrome)
  • 使用方式:
    • 將 deque 最左邊的項目移除、並回傳它 → 使用 popleft() 函式
    • 最右邊的項目移除、並回傳它 → 使用 pop()
    • 它們會同時從兩端開始,往中間移動
    • 只要兩端的字元相符,它就會繼續 pop,直到到達最中間為止
>>> def palindrome(word):
    from collections import deque
    dq = deque(word)
    while len(dq) > 1:
        if dq.popleft() != dq.pop():
            return False
    return True

>>> palindrome('a')
True
>>> palindrome('racecar')
True
>>> palindrome('')
True
>>> palindrome('radar')
True
>>> palindrome('halibut')
False

快速的回文檢查器

  • 目的:為了簡單地說明 deque
  • 簡單做法:將「字串」與「它自己的相反」比較 → 可以用 slice 來反轉字串(Python 沒有字串的 reverse()函式)
>>> def another_palindrome(word):
    return word == word[::-1]            # 將「字串」與「它自己的相反」比較 → 可以用 slice 來反轉字串

>>> another_palindrome('radar')
True
>>> another_palindrome('halibut')
False

迭代程式結構【使用 itertools】

  • itertools(https://docs.python.org/3/library/itertools.html) 裡面有一些特殊的「迭代函式」
  • 在 for...in 迴圈中呼叫它們時 → 會一次回傳一個項目,並且記得每次呼叫之間的狀態
  • itertools 模組還有許多函式,特別是有些排列與組合可以為你節省很多時間

逐一經過它的引數,就像它們是可迭代的單一項目【使用 chain()】

>>> import itertools
>>> for item in itertools.chain([數字1, 數字2], ['文字1', '文字2']):
        print(item)

數字1
數字2
文字1
文字2
>>> import itertools
>>> for item in itertools.chain([1, 2], ['a', 'b']):
    print(item)

1
2
a
b

無限迭代器,會循環經過它的引數【使用 cycle()】

>>> import itertools
>>> for item in itertools.cycle([數字1, 數字2]):
        print(item)

數字1
數字2
數字1
數字2
  .
  .
  .
>>> import itertools
>>> for item in itertools.cycle([1, 2]):
        print(item)

1
2
1
2
.
.
.

【accumulate() 使用方法一】計算累計的值 → 在預設情況下,它會計算總和

>>> import itertools
>>> for item in itertools.accumlate([數字1, 數字2, 數字3, 數字4]):
        print(item)

數字1
數字1 + 數字2
數字1 + 數字2 + 數字3
數字1 + 數字2 + 數字3 + 數字4
.

>>> import itertools
>>> for item in itertools.accumulate([1, 2, 3, 4]):
    print(item)

1
3
6
10

【accumulate() 使用方法二】第二個引數提供一個函式 → 它會被用來取代加法

  • 在 accumulate()第二個引數提供一個函式 → 它會被用來取代加法
>>> import itertools
>>> def multiply(引數1, 引數2):
        return 引數1 * 引數2

>>> for item in itertools.accumulate([數字1, 數字2, 數字3, 數字4], multiply):
        print(item)

數字1
數字1 * 數字2
數字1 * 數字2 * 數字3
數字1 * 數字2 * 數字3 * 數字4
>>> for item in itertools.accumulate([1, 2, 3, 4], multiply):
    print(item)

1
2
6
24

印出好看的結果【使用 pprint()】

  • 我們的範例都使用 print()(或是在互動式解譯器中,只使用變數名稱)來印出東西
  • 有時結果會難閱讀,所以需要更棒的輸出程式 → 例如 pprint()
  • print() → 只會將東西傾印出來
  • pprint() → 會試著排列元素,讓你更容易閱讀
>>> from pprint import pprint
>>> tuple名稱 = OrderedDict([
        ('鍵1': '值1'),
        ('鍵2': '值2'),
        ('鍵3': '值3'),
        ])

# print() → 只會將東西傾印出來
>>> print(tuple名稱)
OrderedDict([('鍵1': '值1'), ('鍵2': '值2'), ('鍵3': '值3')])
>>> from pprint import pprint
>>> from collections import OrderedDict
>>> quotes = OrderedDict([
    ('Moe', 'A wise guy, huh?'),
    ('Larry', 'Ow!'),
    ('Curly', 'Nyuk nyuk!')
    ])
>>> print(quotes)
OrderedDict([('Moe', 'A wise guy, huh?'), ('Larry', 'Ow!'), ('Curly', 'Nyuk nyuk!')])

pprint() → 會試著排列元素,讓你更容易閱讀

pprint(tuple名稱) {'鍵1': '值1', '鍵2': '值2' '鍵3': '值3'} ```

>>> from pprint import pprint
>>> from collections import OrderedDict
>>> quotes = OrderedDict([
    ('Moe', 'A wise guy, huh?'),
    ('Larry', 'Ow!'),
    ('Curly', 'Nyuk nyuk!')
    ])
>>> print(quotes)
OrderedDict([('Moe', 'A wise guy, huh?'), ('Larry', 'Ow!'), ('Curly', 'Nyuk nyuk!')])

>>> pprint(quotes)
OrderedDict([('Moe', 'A wise guy, huh?'),
             ('Larry', 'Ow!'),
             ('Curly', 'Nyuk nyuk!')])

更多電池:取得其他的 Python 程式

  • 有時標準的程式庫沒有你要的東西,或沒有採用非常正確的工作方式
  • 全世界都有開放原始碼、第三方的 Python 軟體供你使用

資源

關於本書

  • 本書幾乎所有的 Python 程式都使用你的電腦所安裝的標準 Python,包括所有內建與標準程式庫
  • 有些地方會使用外部的套件:在第一章提過 requests,並且會在本書第240頁的 "標準程式庫之外:Requests" 進一步說明
  • 本書附錄D 也會展示如何安裝第三方 Python 軟體,以及許多其他的開發細節

results matching ""

    No results matching ""