---
# System prepended metadata

title: Python 神乎其技 Chapter 7
tags: [python]

---

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