# Python 神乎其技 Chapter 7 ###### tags: `python` ## 7-1 在dict查不到鍵時傳回預設值 ### get():有預設值的取值管道 ```python= name_for_userid = { 382: 'Alice', 950: 'Bob', 590: 'Albert' } def greeting(userid): return 'Hello, {}!'.format(name_for_userid[userid]) >>> greeting(590) Hello, Albert! >>> greeting(490) Traceback (most recent call last): File "<pyshell>", line 1, in <module> File "Test.py", line 8, in greeting return 'Hello, {}!'.format(name_for_userid[userid]) KeyError: 490 ``` - 用if else改寫,查詢兩次dict ```python def greeting(userid): if userid in name_for_userid: return 'Hello, {}!'.format(name_for_userid[userid]) else: return 'Hello, Guest!' ``` - EAFP風格:Easier to Ask for Forgiveness than Permission 出錯了用例外事後補救 ```python= def greeting(userid): try: return 'Hello, {}!'.format(name_for_userid[userid]) except: return 'Hello, Guest!' ``` - 回傳預設值 ```python def greeting(userid): return 'Hello, {}!'.format(name_for_userid.get(userid, 'Guest')) ``` ```python >>> greeting(590) Hello, Albert! >>> greeting(490) Hello, Guest! ``` ### setdefault():將預設值加入dict ```python def greeting(userid): return 'Hello, {}!'.format(name_for_userid.setdefault(userid, 'Guest')) >>> greeting(590) Hello, Albert! >>> greeting(490) Hello, Guest! >>> name_for_userid { 382: 'Alice', 950: 'Bob', 590: 'Albert', 490: 'Guest' } ``` - defaultdict vs setdefault() ```python= from collections import defaultdict dog_names = ['Bucky', 'Lucky', 'Randy', 'Buddy', 'Bolt', 'Larry'] dd = defaultdict(list) for name in dog_names: dd[name[0]].append(name) >>> dd.keys() dict_keys(['B', 'L', 'R']) >>> dd['B'] ['Bucky', 'Buddy', 'Bolt'] ``` ```python= data = ['Bucky', 'Lucky', 'Randy', 'Buddy', 'Bolt', 'Larry'] dog_names = dict() for name in data: dog_names.setdefault(name[0], []).append(name) >>> dog_names {'B': ['Bucky', 'Buddy', 'Bolt'], 'L':['Lucky', 'Larry'], 'R': ['Randy']} ``` :::info :round_pushpin: dict()可能查不到,使用EAFP(try,except)攔截錯誤,或是用get()傳回default值 :round_pushpin: 使用setdeault()查不到同時加入default值 ::: ## 7-2 dict元素排序 ### 用sorted()排序 ```python= >>> xs = {'a': 4, 'c': 1, 'd': 3, 'b':2} >>> sorted(xs) ['a', 'b', 'c', 'd'] ``` - 使用dict.items() ```python >>> xs.items() dict_items([('a', 4), ('c', 1), ('d', 3), ('b', 2)]) >>> sorted(xs.items()) [('a', 4), ('b', 2), ('c', 1), ('d', 3)] >>> for key, item in sorted(xs.items()): print(key, item) a 4 b 2 c 1 d 3 >>> ys = dict(sorted(xs.items())) >>> ys {'a': 4, 'b':2, 'c': 1, 'd': 3} >>> xs {'a': 4, 'c': 1, 'd': 3, 'b':2} >>> ys is xs False ``` - view()物件 ```python >>> xs_view = xs.items() >>> xs_view dict_items([('a', 4), ('c', 1), ('d', 3), ('b', 2)]) >>> xs['a'] = 10 >>> xs_view dict_items([('a', 10), ('c', 1), ('d', 3), ('b', 2)]) ``` - Sort by value ```python= >>> sorted(xs.items(), key=lambda x: x[1]) [('c', 1), ('b', 2), ('d', 3), ('a', 4)] >>> sorted(xs.items(), key=lambda x: x[1] ,reverse=True) [('a', 4), ('d', 3), ('b', 2), ('c', 1)] ``` - operator取代lambda ```python= >>> sorted(xs.items(), key=operator.itemgetter(1) ,reverse=True) [('a', 4), ('d', 3), ('b', 2), ('c', 1)] ``` ### 用reversed()產生倒轉的走訪器(python3.8+) ```python >>> xs = {'a': 4, 'c': 1, 'd': 3, 'b':2} >>> reversed(xs.items()) <dict_reverseitemiterator object at 0x000002ACCC7ADEF0> >>> list (reversed(xs.items())) [('b', 2), ('d', 3), ('c', 1), ('a', 4)] >>> for key, item in reversed(xs.items()) print (key, item) b 2 d 3 c 1 a 4 ``` :::info :round_pushpin: 排序dict,用items()產生view物件並用sorted()排序 :round_pushpin: 使用sorted()的key, reverse來決定如何排序 :round_pushpin: reversed()可以建立倒轉的dict走訪器 ::: ## 7-3 用dict模擬C的switch...case語法 ```c= switch(變數名稱或運算式) { case 符合結果1: 程式處理碼; ... break; case 符合結果2: 程式處理碼; ... break; default: 程式處理碼; ... } ``` - Python使用if...elif...else ```python if 變數名稱或運算式 == '符合結果1': 程式處理碼; ... elif 變數名稱或運算式 == '符合結果2': 程式處理碼; ... else: 程式處理碼; ... ``` ### 把dict當成switch ```python= swtich_dict = { '符合結果1': 處理函式1, '符合結果2': 處理函式2, ... } switch_dict[待判斷結果] () ``` ### dict-switch範例 ```python def add(x, y): return x + y def sub(x, y): return x - y def mul(x, y): return x * y def div(x, y): return x / y def default(x, y): return None calculator = { '加': add, '減': sub, '乘': mul, '除': div, } >>> calculator.get('加', default) (1, 2) 3 >>> calculator.get('乘', default) (3, 5) 15 ``` - 減少程式碼 ```python= calculator = { '加': lambda x, y: x + y, '減': lambda x, y: x - y, '乘': lambda x, y: x * y, '除': lambda x, y: x / y, } default = lambda: None ``` - 用函式包裝 ```python= def calculator(x, operator, y): return { '加': lambda x, y: x + y, '減': lambda x, y: x - y, '乘': lambda x, y: x * y, '除': lambda x, y: x / y, }.get(operator, lambda: None) (x, y) >>> calculator(6, '乘', 7) 42 ``` - 減少每次呼叫都建立一次dict ```python cal_dict = { '加': lambda x, y: x + y, '減': lambda x, y: x - y, '乘': lambda x, y: x * y, '除': lambda x, y: x / y, } def calculator(x, operator, y): return cal_dict.get(operator, lambda: None) (x, y) ``` - Python內建operator模組 ```python import operator cal_dict = { '加': operator.add, '減': operator.sub, '乘': operator.mul, '除': operator.truediv, '整除': operator.floordiv, '次方': operator.pow, '無': lambda: None, } def calculator(x, operator, y): return cal_dict.get(operator, cal_dict['無']) (x, y) >>> calculator(10, '整除', 3) 3 ``` :::info :round_pushpin: Python沒有C語言內建的switch...case, 但可以用dict加函式模擬 :round_pushpin: 只適合if...elif...else判斷條件變得過多的時候 :::