python 带有默认值的dict 自定义默认值的dict defaultdictbyKey

工作需要,想写一个类似于collections.defaultdict的字典类型,但是默认值是使用key进行初始化的。参看了defaultdict的实现代码,改造了一个新的类型defaultdictByKey。下面先介绍defaultdict的原理再介绍defaultdictByKey.

defaultdict的原理

defaultdict的直接父类是dict。与dict最大的不同是,当key不存在时,defaultdict会生成一个给定的默认value给key当作value,也就是defaultdict是带有默认值的dict。用法如下:

# 给定一个确定的数值或字符串作为默认值
from collections import defaultdict as ddt
a_dic = ddt(lambda : 1.0)
a_dic["A"]
>>> 1.0

word_count_mapping = ddt(int)
for word in ["word1", "word2", "word3", "word1"]:
	word_count_mapping[word] += 1
print(word_count_mapping)
>>> defaultdict(<type 'int'>, {'word1': 2, 'word3': 1, 'word2': 1})

print(word_count_mapping['word3'])
>>> 0

defaultdict包括两部分:一设置默认值的生成器,二判断key不存在并生成对象并赋值。

defaultdict的源码如下。结合代码我们讲述如何设置给定类型生成器和给新key设置默认值。

class defaultdict(dict):
    """
    defaultdict(default_factory[, ...]) --> dict with default factory
    
    The default factory is called without arguments to produce
    a new value when a key is not present, in __getitem__ only.
    A defaultdict compares equal to a dict with the same items.
    All remaining arguments are treated the same as if they were
    passed to the dict constructor, including keyword arguments.
    """
    ...# 省略其他的代码,一是与此不相关,二是有部分我也不懂你问了我解释不出来,尴尬!
    def __init__(self, default_factory=None, **kwargs): # known case of _collections.defaultdict.__init__
        # 伪代码
        self.default_factory = default_factory
	def __missing__(self, key): # real signature unknown; restored from __doc__
        """
        __missing__(key) # Called by __getitem__ for missing key; pseudo-code:
          if self.default_factory is None: raise KeyError((key,))
          self[key] = value = self.default_factory()
          return value
        """
        # 伪代码
        if self.default_factory is None:
            raise KeyError(key)
        else:
            self[key] = value = self.default_factory()
            return value
            
    default_factory = property(lambda self: object(), lambda self, v: None, lambda self: None)  # default
    """Factory for default value called by __missing__()."""
     

设置给定类型生成器,其__init__的第一个非self参数为default_factory,也就是生成器,factory这个名字和工厂模式相关,确实也是如此,工厂模式属于一种生成式设计模式,这里这个factory生成默认值用的,其常用调用方式如下:

>>> int()
0
>>> word_freq_mapping = defaultdict(int) # 词频映射表,每个新单词的默认值为int()也就是0.
>>> word_freq_mapping[u"大学"] += 1

>>> # 某国家的某个城市的人口数量映射,这是一个二级映射表
>>> country_city_population_mapping = defaultdict(lambda : defaultdict(int)) 
>>> country_city_population_mapping["china"]['beijing'] += 20000000

给新key设置默认值。当我们调用dict的某个key的value时,如word_freq_mapping[u"大学"] += 1其实是调用了dict.__getitem__(key)(不要问为什么,这涉及到底层的python实现和架构),当key不存在时,会直接调用__missing__(self, key)函数。在defaultdict.__missing__中,调用给定生成器生成value,并赋给这个key,最后返回这个value。如果我们没有设置生成器,那么就会报KeyError异常。如下:

>>> from collections import defaultdict as ddt
>>> s = ddt() # 没有设置生成器
>>> s[3] # 
KeyError                                  Traceback (most recent call last)
<ipython-input-22-a93d6738dc8e> in <module>()
      1 from collections import defaultdict as ddt
      2 ss = ddt()
----> 3 print ss[3]

KeyError: 3

defaultdictByKey实现

__missing__的代码中,我们也可以看到,生成器是无参的。而key是参数已经传过来了,那么我们只需要重写这个函数,调用我们给定的有参生成器,即可达到我们的目的。代码如下:

class defaultdictByKey(dict):
    """
    当key不存在时,将key传给自定义的工厂,生成一个value作为key的value。
    >>> key_mapping = defaultdictByKey(lambda x:[x])
    >>> key_mapping[1]
    [1]
    """
    def __init__(self, factory=None, **kwargs):
        super(defaultdictByKey, self).__init__(**kwargs)
        self._factory = factory

    def __missing__(self, key):
        if self._factory != None:
            self[key] = value = self._factory(key)
            return value
        else:
            raise KeyError(key)
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值