第3章:字典和集合-映射的弹性键查询(defaultdict 和 特殊方法 __miss__)

有时候为了方便起见,就算某个键在映射里不存在,我们也希望在通过这个键读取值的时候能得到一个默认值。有两个途径能帮我们达到这个目的,一个是通过 defaultdict 这个类型而不是普通的 dict,另一个是给自己定义一个 dict 的子类,然后在子类中实现 __missing__ 方法。下面将介绍这两种方法。

3.4.1 defaultdict:处理找不到的键的一个选择

        在创建一个 defaultdict 的时候,需要给构造方法提供一个可调用对象,这个可调用对象会在 __getitem__ 碰到找不到的键的时候被调用,让 __getitem__ 调用可调用对象生成一个默认值,并将默认值和键配对放入字典中。

# 新建一个字典,并传入可调用对象 list 和 生成字典的键值对
dd = defaultdict(list, {'a': 1, 'b': 2})

# 键 'c' 在 dd 中还不存在,dd['c'] 会按照以下的步骤来行事:
# 1. 调用 list() 来建立一个新列表;
# 2. 把这个新列表作为值,'c' 作为它的键,放到 dd 中;
# 3. 返回这个列表的引用
rint(dd['c'])  # []
print(dd)  # defaultdict(<class 'list'>, {'a': 1, 'b': 2, 'c': []})

3.4.2 特殊方法 __missing__

        所有的映射类型在处理找不到的键的时候,都会牵扯到 __missing__ 方法。虽然基类 dict 并没有定义这个方法,但是 dict 是知道有这么个东西存在的。也就是说,如果有一个类继承了 dict,然后这个继承类提供了 __missing__ 方法,那么在 __getitem__ 碰到找不到的键的时候,Python 就会自动调用它,而不是抛出一个 KeyError 异常。

class StrKeyDict(dict):
    """自定义字典类,一般自定义字典类应该是继承 collections.UserDict,此处仅做展示 __miss__ 的用法"""
    
    def get(self, key, default=None):
        try:
            # 1. get方法把查询工作以 dict[key] 的形式委托给 __getitem__,假如查询失败,__getitem__会先调用 __miss__
            return self[key]
        # 4. 当 __miss__ 也查询失败抛出 KeyError 异常时捕获异常,然后返回默认值
        except KeyError:
            return default

    # 2. 当查询失败时,__getitem__会先调用 __miss__
    def __missing__(self, key):
        # 3. 检查 key 是不是 str 类型,不过不是,就转为字符串再查询一次,如果本身就是字符串,会抛出 KeyError 异常
        if isinstance(key, str):
            raise KeyError(key)
        return self[str(key)]
    
    # 配套修改
    def __contains__(self, key):
        return key in self.keys() or str(key) in self.keys()

        为了保持一致性,__contains__ 方法在这里也是必需的。这是因为 k in d 这个操作会调用它,但是我们从 dict 继承到的 __contains__ 方法不会在找不到键的时候调用 __missing__ 方法。__contains__ 里还有个细节,就是我们这里没有用更具 Python 风格的方式——k in my_dict——来检查键是否存在,因为那也会导致 __contains__ 被递归调用。为了避免这一情况,这里采取了更显式的方法,直接在这个 self.keys() 里查询。 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值