Python进阶编程:编写更高效、优雅的Python代码
上QQ阅读APP看书,第一时间看更新

3.2.2 字典映射

在实际应用中,一个键对应一个值的映射不能满足所有需求,有时需要通过一个关键值获取多个值,即一个键对应多个值。

字典是一个键对应单值的映射。如果想要一个键映射多个值,只需将多个值放到另外的容器中,比如列表或者集合里,再通过一个键获取该列表或集合即可。比如,可以像下面这样构造对应的字典:


exp_dict_1 = {
    'a': [1, 3, 5],
    'b': [2, 4]
}

exp_dict_2 = {
    'a': {'a', 'b', 'c'},
    'b': {'c', 'd'}
}
exp_dict_3 = {
    'a': {'b': '1'},
    'b': {'c': 2}
}

选择使用列表还是集合取决于实际应用需求。

如果想保持元素的插入顺序就应该使用列表;如果想去掉重复元素可以使用Set集合,但Set集合不保证元素的顺序;使用字典可以去掉重复的key,字典也是无序的。不过,collections模块中提供了一个OrderedDict类,该类可以保证字典的顺序。

我们可以使用collections模块中的defaultdict来构造字典。defaultdict的一个特征是它会自动初始化每个key刚开始对应的值,我们只需要关注添加元素的操作,示例如下:


from collections import defaultdict

default_dict = defaultdict(list)
default_dict['a'].append(1)
default_dict['b'].append(3)

default_dict = defaultdict(set)
default_dict['a'].add(1)
default_dict['b'].add(2)

注意 defaultdict会自动为将要访问的键(就算目前字典中并不存在这样的键)创建映射实体。如果不需要这样的特性,可以在一个普通的字典上使用setdefault()方法来代替,示例如下:


d_dict = dict()
d_dict.setdefault('a', []).append(1)
d_dict.setdefault('b', []).append(2)

不过,很多程序员觉得setdefault()方法用起来有点别扭,因为每次调用都得创建一个新的初始值的实例(如示例中的空列表[])。

一般来讲,创建一个多值映射字典是很简单的。但如果选择自己实现,值的初始化编写代码会更多,并且可读性会降低。我们可以使用如下方式编写代码:


# 原始手动方式
define_dict = dict()
for key, value in key_value_items:
    if key not in define_dict:
        define_dict[key] = []
    define_dict[key].append(value)

使用defaultdict精简后代码如下:


# 改进实现方式
define_dict = defaultdict(list)
for key, value in key_value_items:
    define_dict[key].append(value)

由示例代码可见,使用defaultdict后,代码量少,代码更具可读性。所以,建议读者在工作中尽量用defaultdict代替手动实现。