您不必指定默认工厂(但如果您明确传递None
则相同)
>>> from collections import defaultdict
>>> defaultdict()
defaultdict(None, {})
>>> defaultdict(None)
defaultdict(None, {})
为什么None
?然后我们得到这个东西:
>>> dd = defaultdict()
>>> dd[0]
# TypeError: 'NoneType' object is not callable <-- expected behaviour
# KeyError: 0 <-- actual behaviour
甚至明确允许,因为如果您尝试从其他对象创建默认dict,defaultdict(0)
说,则检查失败
TypeError: first argument must be callable or None
我认为像lambda: None
这样的东西会是一个更好的默认工厂。为什么default_factory
是可选的?我不了解用例。
答案 0 :(得分:5)
当Guido van Rossum initially proposed a DefaultDict
具有默认值(与使用函数而不是值的当前defaultdict
不同)在构造期间设置并被读取-only(也不像defaultdict
)。
经过一番讨论Guidio revised the proposal。以下是相关要点:
很多人建议使用工厂功能代替 默认值。这确实是一个更好的主意(虽然略有一点 对于最简单的情况更麻烦。)
...
让我们在dict类中添加一个通用的缺失键处理方法,如 以及初始化为
None
的default_factory插槽。...
[T]他设计了默认实现,以便我们可以编写
d = {} d.default_factory = list
需要注意的重要一点是,新功能不再属于子类。这意味着在构造函数中设置default_factory
会破坏现有代码。因此,通过设计设置default_factory
必须在创建dict
之后发生。它的初始值设置为None
,它现在是一个可变属性,因此可以被有意义地覆盖。
经过更多讨论之后,我们决定最好不要将常规dict
类型与defaultdict
专业化复杂化。
史蒂文·贝德哈德然后asked for clarification regarding the constructor:
default_factory应该是构造函数的参数吗?他们三个 答案我看到了:
- “否”。我不是这个答案的忠实粉丝。由于创建defaultdict类型的重点是提供默认值,因此需要两个 语句(构造函数调用和default_factory赋值) 初始化这样的字典似乎有点不方便。
- “是的,它应该跟随所有正常的dict构造函数参数。”这没关系,但有一些错误,比如
defaultdict({1:2})
将默默通过(直到您尝试使用 dict,当然)。- “是的,它应该是唯一的构造函数参数。”这是我的最爱,主要是因为我认为它很简单,我想不到 我真正想做
defaultdict(list, some_dict_or_iterable)
或defaultdict(list, **some_keyword_args)
的好例子。如果我们需要在以后添加一些dict构造函数args,它也是向前兼容的。
Guido van Rossum decided that:
defaultdict签名采用可选的位置参数 是default_factory,默认为None。剩下的位置 并且所有关键字参数都传递给dict构造函数。 IOW:
d = defaultdict(list, [(1, 2)])
相当于:
d = defaultdict() d.default_factory = list d.update([(1, 2)])
请注意,当Guido考虑更改dict
以提供defaultdict
行为时,扩展代码完全反映了它的工作方式。
他还提供some justifications upthread:
即使将default_factory传递给构造函数,它仍然存在 应该是一个可写的属性,所以它可以被内省和 改性。默认情况下,无法更改其默认工厂 它的创造不太有用。
Bengt Richter explains why you might want a mutable default factory:
我的猜测是真实地使用default_factory来制作 用于填写字典的干净代码,然后关闭工厂 它将被传递到未知的上下文中。然后可以使用这些上下文 旧代码如上所述,或者如果值得的话可以暂时设置工厂 做一些工作。我认为可以通过紧密耦合的代码 工厂启用的彼此之间的决定。
答案 1 :(得分:1)
我的猜测是,设计是有意的,以便使defaultdict
实例默认情况下像普通字典一样,同时允许稍后通过简单属性访问动态修改行为。
例如:
>>> d = defaultdict()
>>> d['k'] # hey I'm just a plain old dict ;)
KeyError: 'k'
>>> d.default_factory = list
>>> d['L'] # actually, I'm really a defaultdict(list)
[]
>>> d.default_factory = int # just kidding! I'm a counter
>>> d['i']
0
>>> d
defaultdict(int, {'L': [], 'i': 0})
我们可以通过将工厂设置回KeyError
将其重置为看起来像香草字典(将再次引发None
)的东西。
我还没有找到一个可能有用的模式,但是如果它被强制用一个可调用的位置参数实例化默认dict,那么这种用法是不可能的。