# 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判斷條件變得過多的時候
:::