Python 字典默认值,Python的字典有一个get()
方法,在查找键的时候会提供备选值。这个方法适用于许多情况。下面通过一个简单的例子演示一下。假设有以下数据结构将用户ID映射到用户名:
name_for_userid = {
382: 'Alice',
950: 'Bob',
590: 'Dilbert',
}
现在想用这个数据结构编写一个greeting()
函数,根据用户ID向用户返回问候语。第一个实现看起来可能像这样:
def greeting(userid):
return 'Hi %s!' % name_for_userid[userid]
这进行了直观的字典查找。不过这个实现只有在用户ID位于name_for_userid
字典中时才能正常工作。如果向greeting
函数传递无效的用户ID则会抛出异常:
>>> greeting(382)
'Hi Alice!'
>>> greeting(33333333)
KeyError: 33333333
我们并不希望看到KeyError
异常,因此最好在找不到用户ID时,让函数返回一个通用的问候语作为备选。
下面来实现这个想法。首先想到的可能是在字典中查找键,如果找不到这个用户ID就返回默认问候语:
def greeting(userid):
if userid in name_for_userid:
return 'Hi %s!' % name_for_userid[userid]
else:
return 'Hi there!'
对这个greeting()
实现使用之前的测试用例:
>>> greeting(382)
'Hi Alice!'
>>> greeting(33333333)
'Hi there!'
好多了,未知用户现在会得到通用的问候语,而在找到有效用户ID时会得到个性化的问候语。
虽然这个新实现能得到预期的结果,并且看起来短小简洁,但仍然可以改进。目前的方法有如下几个缺点。
- 效率低下,需要查询字典两次。
-
冗长,问候字符串有些重复。
-
不够有Python特色,官方Python文档特别建议使用“请求原谅比获得许可要容易”(easier to ask for forgiveness than permission,EAFP)的编码风格:
这种通用的Python编码风格会先假定存在有效的键或属性,如果假设错误再捕获异常。
基于EAFP原则还有一种更好的实现,即不显式检查键是否包含在内,而是使用try...except
块捕获KeyError
:
def greeting(userid):
try:
return 'Hi %s!' % name_for_userid[userid]
except KeyError:
return 'Hi there'
这种实现也满足最初的要求,而且无须查询字典两次。
然而还能将其进一步改进成更简洁的方案。Python的字典上有get()
方法,其中可以传递一个用作备选值的“默认”参数:
def greeting(userid):
return 'Hi %s!' %
name_for_userid.get( userid, 'there')
当调用get()
时,它会检查字典中是否存在给定的键。如果存在,则返回该键对应的值。如果不存在,则返回默认的备选值。从上面可以看到,这个greeting
的实现仍然按照预期工作:
>>> greeting(950)
'Hi Bob!'
>>> greeting(333333)
'Hi there!'
最终版的greeting()
实现干净简洁,只用到了Python标准库中的特性。因此我认为这是针对这种特殊情况的最佳解决方案。
关键要点
-
测试包含关系时应避免显式检查字典的键。
-
建议使用EAFP风格的异常处理或使用内置的
get()
方法。 -
在某些情况下,可以使用标准库中的
collections.defaultdict
类。