"setdefault"dict方法的用例

Eli*_*sky 181 python dictionary setdefault

加入collections.defaultdict在Python 2.5大大降低用于需要dictsetdefault方法.这个问题适合我们的集体教育:

  1. setdefault今天在Python 2.6/2.7中还有什么用处?
  2. 哪些流行的用例setdefault被取代了collections.defaultdict

Joc*_*zel 194

你可以说defaultdict是设置默认有用填充字典之前setdefault是设置默认值有用,同时或填充字典之后.

可能是最常见的用例:分组项目(未分类数据,否则使用itertools.groupby)

# really verbose
new = {}
for (key, value) in data:
    if key in new:
        new[key].append( value )
    else:
        new[key] = [value]


# easy with setdefault
new = {}
for (key, value) in data:
    group = new.setdefault(key, []) # key might exist already
    group.append( value )


# even simpler with defaultdict 
new = defaultdict(list)
for (key, value) in data:
    new[key].append( value ) # all keys have a default already
Run Code Online (Sandbox Code Playgroud)

有时您希望在创建dict后确保存在特定键.defaultdict在这种情况下不起作用,因为它只在显式访问时创建密钥.认为你使用HTTP-ish和许多标题 - 有些是可选的,但你想要它们的默认值:

headers = parse_headers( msg ) # parse the message, get a dict
# now add all the optional headers
for headername, defaultvalue in optional_headers:
    headers.setdefault( headername, defaultvalue )
Run Code Online (Sandbox Code Playgroud)

  • 或者只是做`new.setdefault(key,[]).append(value)` (16认同)
  • Muhammad Alkarouri:你首先要做的是复制字典,然后覆盖一些项目。我也经常这样做,我想这实际上是最喜欢“setdefault”的习惯用法。另一方面,如果不是所有的 `defaultvalues` 都相等(即有些是 `0`,有些是 `[]`),则 `defaultdict` 将无法工作。 (2认同)
  • @ YHC4k,是的。这就是为什么我使用`headers = dict(optional_headers)`。对于默认值不完全相等的情况。最终结果与先获取HTTP标头然后为未获取的HTTP标头设置默认值相同。如果您已经有`optional_headers`,这将非常有用。试试我给定的两步代码,并将其与您的代码进行比较,您会明白我的意思。 (2认同)
  • 我觉得奇怪的是,最好的答案归结为 `defaultdict` 甚至比 `setdefault` 更好(那么现在用例在哪里?)。此外,`ChainMap` 会更好地处理 `http` 示例,IMO。 (2认同)

Mat*_*ner 28

我通常setdefault用于关键字参数dicts,例如在这个函数中:

def notify(self, level, *pargs, **kwargs):
    kwargs.setdefault("persist", level >= DANGER)
    self.__defcon.set(level, **kwargs)
    try:
        kwargs.setdefault("name", self.client.player_entity().name)
    except pytibia.PlayerEntityNotFound:
        pass
    return _notify(level, *pargs, **kwargs)
Run Code Online (Sandbox Code Playgroud)

在包含关键字参数的函数的包装器中调整参数是很好的.


Dav*_*rek 15

defaultdict 当默认值是静态时(例如新列表)很好,但如果它是动态的则不是很好.

例如,我需要一个字典来将字符串映射到唯一的int.defaultdict(int)将始终使用0作为默认值.同样,defaultdict(intGen())总是产生1.

相反,我使用了常规字典:

nextID = intGen()
myDict = {}
for lots of complicated stuff:
    #stuff that generates unpredictable, possibly already seen str
    strID = myDict.setdefault(myStr, nextID())
Run Code Online (Sandbox Code Playgroud)

请注意,这dict.get(key, nextID())是不够的,因为我需要稍后能够引用这些值.

intGen 是我构建的一个小类,它自动递增一个int并返回它的值:

class intGen:
    def __init__(self):
        self.i = 0

    def __call__(self):
        self.i += 1
    return self.i
Run Code Online (Sandbox Code Playgroud)

如果有人有办法做到这一点,defaultdict我很乐意看到它.

  • 你可以用`itertools.count()替换`intGen`.next`. (7认同)
  • 每次调用`myDict.setdefault()`时,`nextID()`的值都会递增,即使它返回的值不被用作`strID`.这似乎在某种程度上是浪费的,并且说明了我一般不喜欢`setdefault()`的事情之一 - 即它总是评估它的`default`参数,无论它是否实际被使用. (6认同)
  • 要获得您使用 defaultdict 描述的行为,为什么不只是 `myDict = defaultdict(nextID)`? (4认同)

pic*_*e 涅 14

正如大多数答案所述,setdefault或者defaultdict让您在键不存在时设置默认值。但是,我想指出一个关于setdefault. 当 Python 解释器执行时setdefault,即使键存在于字典中,它也会始终评估函数的第二个参数。例如:

In: d = {1:5, 2:6}

In: d
Out: {1: 5, 2: 6}

In: d.setdefault(2, 0)
Out: 6

In: d.setdefault(2, print('test'))
test
Out: 6
Run Code Online (Sandbox Code Playgroud)

如您所见,print即使字典中已经存在 2 也被执行。如果您计划将其setdefault用于诸如memoization. 如果将递归函数调用添加为 的第二个参数setdefault,则不会从中获得任何性能,因为 Python 将始终以递归方式调用该函数。

由于提到了记忆化,如果您考虑使用记忆化增强功能,更好的选择是使用 functools.lru_cache 装饰器。lru_cache 更好地处理递归函数的缓存要求。


And*_*eek 9

setdefault()当我想要一个默认值时,我使用OrderedDict.没有标准的Python集合可以同时执行这两种操作,但是有一些 方法可以实现这样的集合.


Dav*_*rek 7

正如穆罕默德所说,在某些情况下,您有时只希望设置默认值.一个很好的例子是首先填充,然后查询的数据结构.

考虑一个特里.添加单词时,如果需要子节点但不存在,则必须创建子节点以扩展trie.在查询单词的存在时,缺少的子节点表示该单词不存在且不应创建.

defaultdict无法执行此操作.相反,必须使用带有get和setdefault方法的常规字典.


Muh*_*uri 5

从理论上讲,setdefault如果你有时想要设置默认值而有时不设置默认值,那么仍然会很方便.在现实生活中,我没有遇到过这样的用例.

但是,一个有趣的用例来自标准库(Python 2.6,_threadinglocal.py):

>>> mydata = local()
>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]
Run Code Online (Sandbox Code Playgroud)

我会说使用__dict__.setdefault是一个非常有用的案例.

编辑:碰巧,这是标准库中唯一的例子,它在评论中.因此,证明存在的合理性可能还不够setdefault.不过,这里有一个解释:

对象将其属性存储在__dict__属性中.实际上,该__dict__属性在对象创建后的任何时候都是可写的.它也是一本字典而不是一本defaultdict.对于一般情况下的对象而言,将其__dict__作为defaultdict因为将使每个对象具有所有合法标识符作为属性是不明智的.所以我无法预见Python对象的任何变化__dict__.setdefault都会被删除,除非它被认为是无用的完全删除它.