为什么defaultdict default_factory默认为None?

时间:2017-03-10 20:29:04

标签: python defaultdict

您不必指定默认工厂(但如果您明确传递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是可选的?我不了解用例。

2 个答案:

答案 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,那么这种用法是不可能的。