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

本文介绍了如何基于Python的collections.defaultdict创建一个自定义字典类型defaultdictByKey,该类型允许使用key来初始化默认值,通过重写__missing__方法实现。文章详细解析了defaultdict的工作原理,并展示了defaultdictByKey的具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工作需要,想写一个类似于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)
<think>我们正在处理一个关于Python字典的问题:当键为None时如何返回默认值。根据用户的问题,我们需要在字典中查找键为None时返回默认值。注意,None是一个有效的键,可以存在于字典中。但是,我们需要注意:在Python中,None是一个特殊的单例对象,通常用于表示空值。在字典中,None可以作为键使用。用户的需求是:当字典的键为None时,返回一个默认值。这类似于我们处理其他键不存在时返回默认值的情况,但这里特别指定了键为None。我们可以使用几种方法:1.使用dict.get(key,default)方法:这个方法在键存在时返回值(即使键是None),不存在时返回默认值。但是,如果键为None且存在于字典中,那么dict.get(None,default)会返回字典中None对应的值,而不是默认值。所以,如果用户希望在键为None时(无论是否存在)都返回默认值,那么这种方法就不适用了。因为当None存在时,它会返回实际值。2.因此,我们需要区分用户的需求:a)用户可能想忽略None键,即当键为None时,不管字典中是否有None键,都返回默认值。b)或者,用户只是想在字典中没有None键时返回默认值,如果有则返回实际值。根据问题描述:“当key为None时如何返回默认值”,这听起来像是无论字典中是否有None键,只要传入的键是None,就返回默认值。但通常,我们不会在字典中存储None键,或者即使存储了,也可能希望特殊处理。然而,标准字典操作不会因为键是None而特殊对待(除非我们显式处理)。所以,我们需要自定义一个行为。我们可以考虑:-写一个函数,先判断key是否为None,如果是则返回默认值;否则,从字典中获取(使用get或直接索引,但为了避免KeyError,可以用get)。-或者,使用条件表达式。但是,请注意用户提供的引用:引用[1]和引用[2]提到了使用get和setdefault方法,但这些方法都是处理键不存在的情况,而不是针对键为None的情况。所以,我们需要明确:用户是否希望当传入的键是None时,不查询字典而直接返回默认值?如果是这样,我们可以:方法1:在调用get之前检查key是否为NoneifkeyisNone:returndefaultelse:returnd.get(key,default)方法2:使用一个函数封装根据用户提供的引用[1]中有一个示例函数:defget_value_or_default(d,key,default=None):returnd.get(key,default)这个函数在key为None时,如果字典d中有None键,就会返回d[None];如果没有,则返回default。但用户的需求可能是:当key为None时,直接返回默认值,而不查询字典。如果是这样,我们需要修改这个函数:修改后的函数:defget_value_with_none_default(d,key,default=None):ifkeyisNone:returndefaultreturnd.get(key,default)这样,当key为None时,直接返回默认值;否则,正常使用get方法。因此,我们需要确认用户的需求:是否要忽略None键(即不查询字典,直接返回默认值)。根据问题描述,我倾向于这种理解。所以,解决方案是:先判断key是否为None,如果是则返回默认值;否则,使用字典的get方法。下面我们给出代码示例:</think>### Python字典处理键为None时返回默认值的方法 在Python中,当字典的键为`None`时返回默认值,可以通过以下方法实现: #### 1. 使用条件判断直接处理 ```python def get_default(d, key, default=None): if key is None: return default return d.get(key, default) # 示例 my_dict = {None: "actual_value", "a": 1} print(get_default(my_dict, None)) # 输出: None (返回默认值) print(get_default(my_dict, None, "fallback")) # 输出: fallback print(get_default(my_dict, "a")) # 输出: 1 ``` #### 2. 使用`dict.get()`方法 ```python # 直接使用get()方法 my_dict = {None: "stored_value"} print(my_dict.get(None, "default")) # 输出: stored_value (返回实际值) print(my_dict.get("missing", "default")) # 输出: default ``` #### 3. 使用`collections.defaultdict` ```python from collections import defaultdict dd = defaultdict(lambda: "DEFAULT") dd[None] = "special_value" # 显式设置None键 print(dd[None]) # 输出: special_value print(dd["missing"]) # 输出: DEFAULT ``` #### 关键区别说明: 1. **条件判断法** 当键为`None`时**强制返回默认值**,忽略字典中实际存储的`None`键值对 数学表达:$f(k) = \begin{cases} \text{default} & \text{if } k = \text{None} \\ \text{dict.get}(k, \text{default}) & \text{otherwise} \end{cases}$ 2. **`dict.get()`方法** 正常查询字典,包括已存储的`None`键值对 数学表达:$f(k) = v \quad \text{if } (k, v) \in \text{dict}, \quad \text{else default}$ 3. **`defaultdict`** 自动处理缺失键,但对显式存储的`None`键仍返回实际值[^5] > ⚠️ 注意:Python字典允许`None`作为有效键值,其哈希值为固定值`id(None)`[^5]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值