4-24日读书笔记——流畅的python

3.4 3.4 3.4 映射的弹性键查询
有时候,如果我们在字典中查询某个键,但同时,我们希望如果该键值对不存在时,也可以返回一个默认值给我们。那么在python 中,有两种途径可以帮我们达到这一效果。

  • 使用defaultDict类型
  • 定义一个dict的子类,然后在子类中实现__missing__方法。

第一种方法我们之前也有用到了,在我们实例化一个defaultDict的时候就需要为他创建一个找不到的键的默认值。
再具体点说:
我们创建一个dict

>>> my_dict = defaultdict(list)

然后我们查找my_dict[‘no’]时,no这个key肯定是不存在的。因此它会调用list()方法来新建一个列表,并且把这个新列表作为值,'no’作为他的键,放入my_dict中,紧接着返回这个列表的引用。

import sys
import re
import collections

WORD_RE = re.compile(r'\w+')

index = collections.defaultdict(list)
with open(sys.argv[0], encoding='utf-8') as fp:
    for line_no, line in enumerate(fp,1):
        for match in WORD_RE.finditer(line):
            word = match.group()
            column_no = match.start()+1
            location = (line_no, column_no)
            index[word].append(location)
for word in sorted(index, key=str.upper):
    print(word, index[word])
append [(15, 25)]
argv [(8, 11), (9, 15)]
as [(9, 42)]
collections [(3, 8), (7, 9)]
column_no [(13, 13), (14, 34)]
...
import [(1, 1), (2, 1), (3, 1)]
in [(10, 23), (11, 19), (16, 10)]
line [(10, 18), (11, 39)]
line_no [(10, 9), (14, 25)]
...
w [(5, 25)]
with [(9, 1)]
word [(12, 13), (15, 19), (16, 5), (17, 11), (17, 23)]
WORD_RE [(5, 1), (11, 22)]

把list构造方法作为default_factory来创建一个defaultdict。
如果index中并没有word记录,那么default——factory就会被调用,为查询不到的键创造一个value——就是一个空的列表。并且该空列表被赋值给了index[word]并且返回。

当然,defaultdict里的default_factory只会在__getitem__中被调用。上个my_dict的例子中,my_dict[‘no’]就会调用default_factory创造默认值。如果使用的是my_dict.get(“no”)则会返回none。

KaTeX parse error: Expected group after '_' at position 5: 特殊方法_̲_ missing__
所有的映射类型如果找不到对应的键,则会用到__missing__方法。
而这个方法只会被__getitem__调用。对get的方式没有影响。

class StrKeyDict0(dict):
    def __missing__(self, key):
        if isinstance(key, str):
            raise KeyError(key)
        return self[str(key)]

    def get(self, k, default=None):
        try:
            return self[k]
        except KeyError:
            return default

    def __contains__(self, key):
        return key in self.keys() or str(key) in self.keys()
        

d = StrKeyDict0([('2', 'two'), ('4', 'four')])
print(d[2])
print(d['4'])
print(d.get("1"))
print(d[1])
two
four
None
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/Applications/PyCharm.app/Contents/helpers/pydev/_pydev_bundle/pydev_umd.py", line 197, in runfile
    pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script
  File "/Applications/PyCharm.app/Contents/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "/Users/xx/PycharmProjects/test/a.py", line 21, in <module>
    print(d[1])
  File "/Users/xx/PycharmProjects/test/a.py", line 5, in __missing__
    return self[str(key)]
  File "/Users/xx/PycharmProjects/test/a.py", line 4, in __missing__
    raise KeyError(key)
KeyError: '1'

该类继承了Dict类,找不到键2时,会用字符串‘2’再找一次,于是d[2]时候返回了two。但是用d[1]的时候,用字符串同样找不到,于是报了KeyError。

我们在创建它的时候,并没有传入的值的类型进行限制,这样也使得我们在查找时十分的友好。

3.5 3.5 3.5 字典的变种

这一小节总结一下标准库collections中的映射类型。

  • collections.OrderedDict

key有顺序的dict,类似Java中的TreeMap

  • collections.ChainMap(*maps)

将多个dict当成一个dict,按顺序搜索key,只要搜索到key,结果返回成功。如果没有maps被指定,就提供一个默认的空字典,这样一个新链至少有一个映射。

  • collections.Counter

持有key的计数,most_common(n)方法会按次序返回映射中最常见的n个键和计数
实例如下:

>>> import collections
>>> ct = collections.Counter('abcdeeafffw')
>>> ct
Counter({'f': 3, 'a': 2, 'e': 2, 'b': 1, 'c': 1, 'd': 1, 'w': 1})
>>> ct.update('fwww')
>>> ct
Counter({'f': 4, 'w': 4, 'a': 2, 'e': 2, 'b': 1, 'c': 1, 'd': 1})
>>> ct.most_common(2)
[('f', 4), ('w', 4)]
  • collections.UserDict([initialdata])

纯Python实现的标准dict
一般来说userDict被用来供其他几个直接使用。这个实例的内容保存为一个正常字典,可以通过UserDict实例的data属性存取。如果提供了initialdata值,data就被初始化为它的内容。

如果我们想要自定义一个类,最好是继承UserDict,这样的话我们可以避免一些不必要的重写。
那上一个StrKeyDict()的例子来说:

class StrKeyDict0(dict):
    def __missing__(self, key):
        if isinstance(key, str):
            raise KeyError(key)
        return self[str(key)]

    def __contains__(self, key ):
        return str(key) in self.data
    
    def __setitem__(self, key, item):
        self.data[str(key)] = item

它的data属性实际上是它最终存储数据的地方。
UserDict继承的是MutableMapping类
dict对象的最原始的接口描述是 collections 模块中的 Mapping 和 MutableMapping 这两个虚拟类,如下所示:
在这里插入图片描述
因此在后一个实例中,就不用再改写__get__方法了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值