Python “setdefault” dict 方法的用例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3483520/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:17:57  来源:igfitidea点击:

Use cases for the 'setdefault' dict method

pythondictionarysetdefault

提问by Eli Bendersky

The addition of collections.defaultdictin Python 2.5 greatly reduced the need for dict's setdefaultmethod. This question is for our collective education:

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

  1. What is setdefaultstill useful for, today in Python 2.6/2.7?
  2. What popular use cases of setdefaultwere superseded with collections.defaultdict?
  1. 什么是setdefault仍然有用,今天在Python 2.6 / 2.7?
  2. 哪些流行的用例setdefault被取代collections.defaultdict

采纳答案by Jochen Ritzel

You could say defaultdictis useful for settings defaults before filling the dictand setdefaultis useful for setting defaults while or after filling the dict.

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

Probably the most common use case: Grouping items (in unsorted data, else use itertools.groupby)

可能最常见的用例:分组项目(在未排序的数据中,否则使用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 
from collections import defaultdict
new = defaultdict(list)
for (key, value) in data:
    new[key].append( value ) # all keys have a default already

Sometimes you want to make sure that specific keys exist after creating a dict. defaultdictdoesn't work in this case, because it only creates keys on explicit access. Think you use something HTTP-ish with many headers -- some are optional, but you want defaults for them:

有时您想确保在创建 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 )

回答by Muhammad Alkarouri

Theoretically speaking, setdefaultwould still be handy if you sometimeswant to set a default and sometimes not. In real life, I haven't come across such a use case.

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

However, an interesting use case comes up from the standard library (Python 2.6, _threadinglocal.py):

然而,标准库(Python 2.6,_threadinglocal.py)中出现了一个有趣的用例:

>>> mydata = local()
>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]

I would say that using __dict__.setdefaultis a pretty useful case.

我会说 using__dict__.setdefault是一个非常有用的案例。

Edit: As it happens, this is the only example in the standard library and it is in a comment. So may be it is not enough of a case to justify the existence of setdefault. Still, here is an explanation:

编辑:碰巧,这是标准库中唯一的示例,并且在注释中。所以可能不足以证明setdefault. 不过,这里有一个解释:

Objects store their attributes in the __dict__attribute. As it happens, the __dict__attribute is writeable at any time after the object creation. It is also a dictionary not a defaultdict. It is not sensible for objects in the general case to have __dict__as a defaultdictbecause that would make each object having all legal identifiers as attributes. So I can't foresee any change to Python objects getting rid of __dict__.setdefault, apart from deleting it altogether if it was deemed not useful.

对象将它们的属性存储在__dict__属性中。碰巧的是,该__dict__属性在对象创建后的任何时间都是可写的。它也是一本字典而不是defaultdict. 在一般情况下,对象具有__dict__作为 a是不明智的,defaultdict因为这会使每个对象都具有所有合法标识符作为属性。因此,我无法预见 Python 对象的任何更改__dict__.setdefault会被删除,除非它被认为没有用处,否则将其完全删除。

回答by Matt Joiner

I commonly use setdefaultfor keyword argument dicts, such as in this function:

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

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)

It's great for tweaking arguments in wrappers around functions that take keyword arguments.

它非常适合在采用关键字参数的函数的包装器中调整参数。

回答by David Kanarek

defaultdictis great when the default value is static, like a new list, but not so much if it's dynamic.

defaultdict当默认值是静态的(比如一个新列表)时很好,但如果它是动态的就不是那么好。

For example, I need a dictionary to map strings to unique ints. defaultdict(int)will always use 0 for the default value. Likewise, defaultdict(intGen())always produces 1.

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

Instead, I used a regular dict:

相反,我使用了一个普通的字典:

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

Note that dict.get(key, nextID())is insufficient because I need to be able to refer to these values later as well.

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

intGenis a tiny class I build that automatically increments an int and returns its value:

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

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

    def __call__(self):
        self.i += 1
    return self.i

If someone has a way to do this with defaultdictI'd love to see it.

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

回答by David Kanarek

As Muhammad said, there are situations in which you only sometimes wish to set a default value. A great example of this is a data structure which is first populated, then queried.

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

Consider a trie. When adding a word, if a subnode is needed but not present, it must be created to extend the trie. When querying for the presence of a word, a missing subnode indicates that the word is not present and it should not be created.

考虑尝试。添加单词时,如果需要但不存在子节点,则必须创建它以扩展树。在查询某个词是否存在时,缺少子节点表示该词不存在,不应创建该词。

A defaultdict cannot do this. Instead, a regular dict with the get and setdefault methods must be used.

defaultdict 不能这样做。相反,必须使用带有 get 和 setdefault 方法的常规字典。

回答by AndyGeek

I use setdefault()when I want a default value in an OrderedDict. There isn't a standard Python collection that does both, but there arewaysto implement such a collection.

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

回答by Stefan Gruenwald

Here are some examples of setdefault to show its usefulness:

以下是 setdefault 的一些示例以显示其实用性:

"""
d = {}
# To add a key->value pair, do the following:
d.setdefault(key, []).append(value)

# To retrieve a list of the values for a key
list_of_values = d[key]

# To remove a key->value pair is still easy, if
# you don't mind leaving empty lists behind when
# the last value for a given key is removed:
d[key].remove(value)

# Despite the empty lists, it's still possible to 
# test for the existance of values easily:
if d.has_key(key) and d[key]:
    pass # d has some values for key

# Note: Each value can exist multiple times!
"""
e = {}
print e
e.setdefault('Cars', []).append('Toyota')
print e
e.setdefault('Motorcycles', []).append('Yamaha')
print e
e.setdefault('Airplanes', []).append('Boeing')
print e
e.setdefault('Cars', []).append('Honda')
print e
e.setdefault('Cars', []).append('BMW')
print e
e.setdefault('Cars', []).append('Toyota')
print e

# NOTE: now e['Cars'] == ['Toyota', 'Honda', 'BMW', 'Toyota']
e['Cars'].remove('Toyota')
print e
# NOTE: it's still true that ('Toyota' in e['Cars'])

回答by woodm1979

I use setdefault frequently when, get this, setting a default (!!!) in a dictionary; somewhat commonly the os.environ dictionary:

当我在字典中设置默认值 (!!!) 时,我经常使用 setdefault;os.environ 字典有点常见:

# Set the venv dir if it isn't already overridden:
os.environ.setdefault('VENV_DIR', '/my/default/path')

Less succinctly, this looks like this:

不那么简洁,这看起来像这样:

# Set the venv dir if it isn't already overridden:
if 'VENV_DIR' not in os.environ:
    os.environ['VENV_DIR'] = '/my/default/path')

It's worth noting that you can also use the resulting variable:

值得注意的是,您还可以使用结果变量:

venv_dir = os.environ.setdefault('VENV_DIR', '/my/default/path')

But that's less necessary than it was before defaultdicts existed.

但这比在 defaultdicts 存在之前没有必要。

回答by Tuttle

Another use case that I don't think was mentioned above. Sometimes you keep a cache dict of objects by their id where primary instance is in the cache and you want to set cache when missing.

我认为上面没有提到的另一个用例。有时,您通过对象的 id 保留对象的缓存字典,其中主实例位于缓存中,并且您希望在丢失时设置缓存。

return self.objects_by_id.setdefault(obj.id, obj)

That's useful when you always want to keep a single instance per distinct id no matter how you obtain an obj each time. For example when object attributes get updated in memory and saving to storage is deferred.

当您总是希望为每个不同的 id 保留一个实例时,这很有用,无论您每次如何获取 obj。例如,当对象属性在内存中更新并推迟保存到存储时。

回答by YvesgereY

[Edit] Very wrong!The setdefault would always trigger long_computation, Python being eager.

[编辑]大错特错!setdefault 总是会触发 long_computation,Python 是急切的。

Expanding on Tuttle's answer. For me the best use case is cache mechanism. Instead of:

扩展塔特尔的回答。对我来说,最好的用例是缓存机制。代替:

if x not in memo:
   memo[x]=long_computation(x)
return memo[x]

which consumes 3 lines and 2 or 3 lookups, I would happily write:

它消耗 3 行和 2 或 3 次查找,我很乐意写

return memo.setdefault(x, long_computation(x))