当键不在字典时,该如何处理?
- 一种方案用 get,为什么是比较好的选择?
一个例子(字典 str-int)
- 例如,我们要给一家三明治店设计菜单,所以想先确定大家喜欢吃哪些类型的面包。
于是,我们定义这样一个字典,把每种款式的名字和它当前的得票数关联起来。
counters = {
'pumpernickel': 2,
'sourdough': 1,
}
1 判断方式
如果要记录新的一票,首先得判断对应的键在不在字典里。
- 如果不在,那就把这个键已经得到的票数默认为 0,然后增加得票数。
- 这需要两次访问这个键
- 第一次是为了判断它在不在字典里,
- 第二次是为了用它来获取对应的值,
- 而且还要做一次赋值。 ```python key = ‘wheat’
- 这需要两次访问这个键
if key in counters: count = counters[key] else: count = 0
counters[key] = count + 1
print(counters)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22011425/1647914852138-f6edafbb-425e-4c16-bcc8-d7b3d2f83a02.png#clientId=ufa0f741f-3cf7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=37&id=ub9b44025&margin=%5Bobject%20Object%5D&name=image.png&originHeight=37&originWidth=458&originalType=binary&ratio=1&rotation=0&showTitle=false&size=5255&status=done&style=none&taskId=u9762ec75-09fe-48c5-9584-d076268cee7&title=&width=458)
<a name="iQSDt"></a>
## 2 利用 keyError 异常
- 只需要访问一次键名就可以了(也就是在试图获取键值的那行语句中)
```python
key = 'brioche'
try:
count = counters[key]
except KeyError:
count = 0
counters[key] = count + 1
print(counters)
3 利用 get 处理
- 第一个参数指定自己想查的键,
- 第二个参数指定这个键不存在时应返回的默认值。 ```python key = ‘multigrain’
count = counters.get(key, 0) counters[key] = count + 1
print(counters)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22011425/1647915207824-dc89ea99-6a26-490d-b29a-8d5dbe8d27dc.png#clientId=ufa0f741f-3cf7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=40&id=u93cb9a2e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=40&originWidth=469&originalType=binary&ratio=1&rotation=0&showTitle=false&size=5391&status=done&style=none&taskId=uce84cfa2-dc2d-446f-b610-b511ae83e56&title=&width=469)
<a name="X7n6D"></a>
# 另外一个例子(字典 str-list)
- 紧接上面的例子,这次不仅要记录每种面包的得票数,而且要记录投票的人。
- 那可以像下面这样,把面包的名称(也就是键名)跟一份列表关联起来,而那份列表指的就是喜欢这种面包的人。
```python
votes = {
'baguette': ['Bob', 'Alice'],
'ciabatta': ['Coco', 'Deb'],
}
1 判断方式
- 判断字典是否有该键,如果有,提取这个 item 作 append
- 否则 ```python key = ‘brioche’ who = ‘Elmer’
if key in votes: names = votes[key] else: names = votes[key] = [] #
names.append(who) print(votes)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22011425/1647917059963-1d14e5a3-a566-4580-8df0-1364ee34aadf.png#clientId=ufa0f741f-3cf7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=37&id=u36ee6154&margin=%5Bobject%20Object%5D&name=image.png&originHeight=37&originWidth=579&originalType=binary&ratio=1&rotation=0&showTitle=false&size=6050&status=done&style=none&taskId=udf82e125-82cf-484b-a462-25915093c59&title=&width=579)
<a name="rALR4"></a>
## 2 利用 keyError 异常
```python
key = 'rye'
who = 'Felix'
try:
names = votes[key]
except KeyError:
votes[key] = names = []
names.append(who)
print(votes)
3 利用 get 处理
key = 'wheat'
who = 'Gertrude'
names = votes.get(key)
if names is None:
votes[key] = names = []
names.append(who)
print(names)
可以用赋值表达式
key = 'brioche'
who = 'Hugh'
if (names := votes.get(key)) is None: # 赋值
votes[key] = names = []
names.append(who)
print(votes)
4 利用 setdefault 方法
- 这个方法会查询字典里有没有这个键,
- 如果有,就返回对应的值;
- 如果没有,就先把用户提供的默认值跟这个键关联起来并插入字典(get不会),
- 然后返回这个值。 ```python key = ‘cornbread’ who = ‘Kirk’
names = votes.setdefault(key, []) names.append(who)
print(votes)
- 可能有点难懂,如果这个键本来就包括值,那么就是返回值而已
<a name="XcR1m"></a>
### 可能产生较大的性能开销
```python
data = {}
key = 'foo'
value = []
data.setdefault(key, value)
print('Before:', data)
value.append('hello')
print('After: ', data)
- 在本例中,这就相当于每次调用时,不管字典里有没有这个键,都得分配一个 list 实例,
- 这有可能产生比较大的性能开销。
回到第一个例子,为什么不用 setdefault
```python counters = { ‘pumpernickel’: 2, ‘sourdough’: 1, }
key = ‘dutch crunch’
counters.setdefault(key, 0) counters[key] += 1
print(counters) ```
- 不管字典里有没有这个键,我们都要递增它所对应的值。
- 在字典里没有这个键的情况下,这种写法会先通过 setdefault 把默认值 0 赋给这个键,然后再通过 counters[key] += 1 把递增之后的值更新到字典中,这其实完全没有必要。
无论字典里有没有这个键
有四种办法可以处理键不在字典中的情况:in 表达式、KeyError 异常、get 方法与 setdefault 方法。
- 如果跟键相关联的值是像计数器这样的基本类型,那么 get 方法就是最好的方案;如果是那种构造起来开销比较大,或是容易出异常的类型,那么可以把这个方法与赋值表达式结合起来使用。
- 即使看上去最应该使用 setdefault 方案,也不一定要真的使用 setdefault 方案,而是可以考虑用 defaultdict 取代普通的 dict 。