字典和集合

泛映射类型

常见的映射方法

方法 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雷同.

posted @ 2018-02-11 14:01  Yuanoung  阅读(313)  评论(0)    收藏  举报