字典和集合
泛映射类型

常见的映射方法
| 方法 | dict | defaultdict | OrderedDict | 說明 |
|---|---|---|---|---|
| d.clear() | • | • | • | 移除所有元素 |
d.__contains__(k) |
• | • | • | 检查 k 是否在 d 中 |
| d.copy() | • | • | • | 浅复制 |
d.__copy__() |
• | 用于支持 copy.copy | ||
| d.default_factory | • | 在 __missing__ 函数中被调用的函数,用以给未找到的元素设置值* |
||
d.__delitem__(k) |
• | • | • | del d[k],移除键为 k 的元素 |
| d.fromkeys(it,[initial]) | • | • | • | 将迭代器 it里的元素设置为映射里的键,如果有 initial参数,就把它作为这些键对应的值(默认是None) |
| d.get(k,[default]) | • | • | • | 返回键 k 对应的值,如果字典里没有键 k,则返回 None或者 default |
d.__getitem__(k) |
• | • | • | 让字典 d 能用 d[k] 的形式返回键 k 对应的值 |
| d.items() | • | • | • | 返回 d 里所有的键值对 |
d.__iter__() |
• | • | • | 获取键的迭代器 |
| d.keys() | • | • | • | 获取所有的键 |
d.__len__() |
• | • | • | 可以用 len(d) 的形式得到字典里键值对的数量 |
d.__missing__(k) |
• | 当 __getitem__ 找不到对应键的时候,这个方法会被调用 |
||
| d.move_to_end(k,[last]) | • | 把键为 k 的元素移动到最靠前或者最靠后的位置( last的默认值是 True) | ||
| d.pop(k, [defaul] | • | • | • | 返回键 k 所对应的值,然后移除这个键值对。如果没有这个键,返回 None 或者 defaul |
| d.popitem() | • | • | • | 随机返回一个键值对并从字典里移除它# |
d.__reversed__() |
• | 返回倒序的键的迭代器 | ||
| d.setdefault(k,[default]) | • | • | • | 若字典里有键k,则把它对应的值设置为 |
d.__setitem__(k,v) |
• | • | • | 实现 d[k] = v 操作,把 k 对应的值设为v |
| d.update(m,[**kargs]) | • | • | • | m 可以是映射或者键值对迭代器,用来更新 d 里对应的条目 |
| d.values() | • | • | • | 返回字典里的所有值 |
代码样例1
my_dict.setdefault(key, []).append(new_value)
# 也可以是下面的寫法
if key not in my_dict:
my_dict[key] = []
my_dict[key].append(new_value)
这个2者的执行效果是一样的,但是只不过后者至少要进行两次键查询——如果键不存在的话,就是三次,用 setdefault 只需要一次就可以完成整个操作。
代码样例2
虽然我们可以利用
index = collections.defaultdict(list)
来创建一个默认值为list的dict.但是有时,我们需要创建默认值为list的dict的dict,这个时候我们应该怎么办呢?这个时候,可以利用lambda表达式来实现:
In [13]: a = defaultdict(lambda: defaultdict(list))
In [14]: a
Out[14]: defaultdict(<function __main__.<lambda>>, {})
In [15]: a['b']['c'].append(3)
In [16]: a
Out[16]: defaultdict(<function __main__.<lambda>>, {'b': defaultdict(list, {'c': [3]})})
映射的弹性键查询
特殊方法__missing__
class StrKeyDict0(dict): # <1>StrKeyDict0 继承了 dict。
def __missing__(self, key):
if isinstance(key, str): # <2>如果找不到的键本身就是字符串,那就抛出 KeyError 异常。
raise KeyError(key)
return self[str(key)] # <3>如果找不到的键不是字符串,那么把它转换成字符串再进行查找。
def get(self, key, default=None):
try:
return self[key] # <4>get 方法把查找工作用 self[key] 的形式委托给 __getitem__,
# 这样在宣布查找失败之前,还能通过 __missing__ 再给某个键一个机会。
except KeyError:
return default # <5>如果抛出 KeyError,那么说明 __missing__ 也失败了,于是返回 default。
def __contains__(self, key):
return key in self.keys() or str(key) in self.keys() # <6>先按照传入键的原本的值来查找(我们的映射类型中可能含有非字符串的键),如果没找到,再用 str() 方法把键转换成字符串再查找一次。
像 k in my_dict.keys() 这种操作在 Python 3 中是很快的,而且即便映射类型对象很庞大也没关系。这是因为 dict.keys() 的返回值是一个“视图”。
集合类型的其他方法
| 方法 | set | frozenset | 说明 |
|---|---|---|---|
| s.add(e) | • | 把元素 e 添加到 s 中 | |
| s.clear() | • | 移除掉 s 中的所有元素 | |
| s.copy() | • | • | 对 s 浅复制 |
| s.discard(e) | • | 如果 s 里有 e 这个元素的话,把它移除 | |
s.__iter__() |
• | • | 返回 s 的迭代器 |
s.__len__() |
• | • | len(s) |
| s.pop() | • | 从 s 中移除一个元素并返回它的值,若 s 为空,则抛出 KeyError 异常 | |
| s.remove(e) | • | 从 s 中移除 e 元素,若 e 元素不存在,则抛出 KeyError 异常 |
dict和set的背后
速度问题
dict与set差不多,但是两者均快于list,相应的,存储的空间也是更大.也就是空间换时间.
散列表算法

dict的实现及其导致的结果
- 键必须是可散列的
- 字典在内存上的开销巨大.
由于字典使用了散列表,而散列表又必须是稀疏的,这导致它在空间上的效率低下. - 键查询很快
- 键的次序取决于添加顺序.
- 往字典里添加新键可能会改变已有键的顺序
所以不要对字典同时进行迭代和修改。在 Python 3 中,.keys()、.items()和.values()方法返回的都是字典视图。
set的实现以及导致的结果
set 和 frozenset 的实现也依赖散列表,但在它们的散列表里存放的只有元素的引用(就像在字典里只存放键而没有相应的值)。性质与dict雷同.

浙公网安备 33010602011771号