“setdefault”命令方法的用例。

时间:2021-09-26 23:06:34

The addition of collections.defaultdict in Python 2.5 greatly reduced the need for dict's setdefault method. This question is for our collective education:

在Python 2.5中添加collections.defaultdict大大减少了对dict的setdefault方法的需要。这个问题是为了我们的集体教育:

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

15 个解决方案

#1


157  

You could say defaultdict is useful for settings defaults before filling the dict and setdefault is 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)

可能是最常见的用例:分组项(在未排序的数据中,else使用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

Sometimes you want to make sure that specific keys exist after creating a dict. defaultdict doesn'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 )

#2


25  

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

我通常使用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)

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

它很好地调整了围绕着关键字参数的函数包装的参数。

#3


13  

defaultdict is 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.

例如,我需要一个字典来将字符串映射到唯一的ints。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())是不够的,因为我以后还需要能够引用这些值。

intGen is 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 defaultdict I'd love to see it.

如果有人有办法用defaultdict来做这个,我很乐意看到。

#4


9  

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

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

#5


6  

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.

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

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.

考虑一个单词查找树。当添加一个单词时,如果需要一个子节点,但不存在,必须创建它来扩展trie。当查询一个单词的存在时,一个缺失的子节点表示这个单词不存在,它不应该被创建。

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

违约者不能这样做。相反,必须使用get和setdefault方法的常规命令。

#6


5  

Theoretically speaking, setdefault would still be handy if you sometimes want 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__.setdefault is a pretty useful case.

我想说的是使用__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 defaultdict because 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__属性在对象创建之后的任何时间都可以写。它也是一本词典,而不是一种默认的词典。对于一般情况下的对象来说,将__dict__作为defaultdict是不明智的,因为这会使每个对象具有所有合法的标识符作为属性。因此,我无法预见Python对象的任何更改都将删除__dict__。setdefault,如果它被认为是无用的,则完全删除它。

#7


2  

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'])

#8


2  

A likely drawback of defaultdict over dict (dict.setdefault) is that a defaultdict object creates a new item everytime non existing key is given (eg with print, ==). Also defaultdict class is way less common then dict class (serialization, representation, etc).

default命令的一个可能的缺点是,defaultdict对象每次都创建一个新项(如print, ==)。同样,defaultdict类也不是常见的命令类(序列化、表示等)。

P.S. IMO functions (methods) not meant to mutate an object, should not mutate an object.

IMO函数(方法)不是用来改变对象的,不应该改变对象。

#9


1  

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

我经常使用setdefault,在字典中设置默认值(!!!)有些常见的操作系统。环境字典:

# 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.

但这比违约之前的情况要少得多。

#10


1  

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.

这很有用,当您每次都想要保持一个单独的实例时,无论您如何获得一个obj。例如,当对象属性在内存中被更新时,保存到存储被延迟。

#11


1  

One very important use-case I just stumbled across: dict.setdefault() is great for multi-threaded code when you only want a single canonical object (as opposed to multiple objects that happen to be equal).

我偶然发现的一个非常重要的用例是:dict.setdefault()对于多线程代码非常好,当您只想要一个单一的规范对象(而不是多个恰好相等的对象时)。

For example, the (Int)Flag Enum in Python 3.6.0 has a bug: if multiple threads are competing for a composite (Int)Flag member, there may end up being more than one:

例如,Python 3.6.0中的(Int)标志枚举有一个错误:如果多个线程争用一个复合(Int)标志成员,那么可能会出现多个线程:

from enum import IntFlag, auto
import threading

class TestFlag(IntFlag):
    one = auto()
    two = auto()
    three = auto()
    four = auto()
    five = auto()
    six = auto()
    seven = auto()
    eight = auto()

    def __eq__(self, other):
        return self is other

    def __hash__(self):
        return hash(self.value)

seen = set()

class cycle_enum(threading.Thread):
    def run(self):
        for i in range(256):
            seen.add(TestFlag(i))

threads = []
for i in range(8):
    threads.append(cycle_enum())

for t in threads:
    t.start()

for t in threads:
    t.join()

len(seen)
# 272  (should be 256)

The solution is to use setdefault() as the last step of saving the computed composite member -- if another has already been saved then it is used instead of the new one, guaranteeing unique Enum members.

解决方案是使用setdefault()作为保存计算组合成员的最后一步——如果已经保存了另一个成员,则使用setdefault()来代替新成员,以保证唯一的Enum成员。

#12


0  

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

[编辑]非常错误!setdefault总是会触发long_计算,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))

#13


0  

When the required default value is not always the same, or it's only desired for specific keys but it's preferred not to have one for others, one might consider using setdefault:

当所需的默认值不总是相同的时候,或者只需要特定的键值,但不希望为其他键使用时,可以考虑使用setdefault:

d = {}
...
# `i` should default to zero
i = d.setdefault(key, 0)
...
# `s` should default to an empty string
s = d.setdefault(key, '')
...

 

 

d = {}
...
# v should always default to a list
v = d.setdefault(key, [])
...
try:
    # EAFP, but I need the dict to raise a KeyError if the key is not found.
    w = d[k2]
except KeyError:
    ...
...

#14


0  

I like the answer given here:

我喜欢这里给出的答案:

http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html

http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html

In short, the decision (in non-performance-critical apps) should be made on the basis of how you want to handle lookup of empty keys downstream (viz. KeyError versus default value).

简而言之,这一决定(在非性能关键的应用程序中)应该基于你想要如何处理下游的空键(viz. KeyError与默认值)。

#15


0  

The different use case for setdefault() is when you don't want to overwrite the value of an already set key. defaultdict overwrites, while setdefault() does not. For nested dictionaries it is more often the case that you want to set a default only if the key is not set yet, because you don't want to remove the present sub dictionary. This is when you use setdefault().

setdefault()的不同用例是当您不想覆盖已设置的密钥的值时。defaultdict重写,而setdefault()则没有。对于嵌套字典,通常情况下,只有当键尚未设置时,您才想设置默认值,因为您不想删除当前的子字典。这是使用setdefault()的时候。

Example with defaultdict:

与defaultdict示例:

>>> from collection import defaultdict()
>>> foo = defaultdict()
>>> foo['a'] = 4
>>> foo['a'] = 2
>>> print(foo)
defaultdict(None, {'a': 2})

setdefault doesn't overwrite:

setdefault不覆盖:

>>> bar = dict()
>>> bar.setdefault('a', 4)
>>> bar.setdefault('a', 2)
>>> print(bar)
{'a': 4}

#1


157  

You could say defaultdict is useful for settings defaults before filling the dict and setdefault is 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)

可能是最常见的用例:分组项(在未排序的数据中,else使用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

Sometimes you want to make sure that specific keys exist after creating a dict. defaultdict doesn'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 )

#2


25  

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

我通常使用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)

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

它很好地调整了围绕着关键字参数的函数包装的参数。

#3


13  

defaultdict is 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.

例如,我需要一个字典来将字符串映射到唯一的ints。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())是不够的,因为我以后还需要能够引用这些值。

intGen is 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 defaultdict I'd love to see it.

如果有人有办法用defaultdict来做这个,我很乐意看到。

#4


9  

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

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

#5


6  

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.

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

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.

考虑一个单词查找树。当添加一个单词时,如果需要一个子节点,但不存在,必须创建它来扩展trie。当查询一个单词的存在时,一个缺失的子节点表示这个单词不存在,它不应该被创建。

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

违约者不能这样做。相反,必须使用get和setdefault方法的常规命令。

#6


5  

Theoretically speaking, setdefault would still be handy if you sometimes want 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__.setdefault is a pretty useful case.

我想说的是使用__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 defaultdict because 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__属性在对象创建之后的任何时间都可以写。它也是一本词典,而不是一种默认的词典。对于一般情况下的对象来说,将__dict__作为defaultdict是不明智的,因为这会使每个对象具有所有合法的标识符作为属性。因此,我无法预见Python对象的任何更改都将删除__dict__。setdefault,如果它被认为是无用的,则完全删除它。

#7


2  

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'])

#8


2  

A likely drawback of defaultdict over dict (dict.setdefault) is that a defaultdict object creates a new item everytime non existing key is given (eg with print, ==). Also defaultdict class is way less common then dict class (serialization, representation, etc).

default命令的一个可能的缺点是,defaultdict对象每次都创建一个新项(如print, ==)。同样,defaultdict类也不是常见的命令类(序列化、表示等)。

P.S. IMO functions (methods) not meant to mutate an object, should not mutate an object.

IMO函数(方法)不是用来改变对象的,不应该改变对象。

#9


1  

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

我经常使用setdefault,在字典中设置默认值(!!!)有些常见的操作系统。环境字典:

# 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.

但这比违约之前的情况要少得多。

#10


1  

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.

这很有用,当您每次都想要保持一个单独的实例时,无论您如何获得一个obj。例如,当对象属性在内存中被更新时,保存到存储被延迟。

#11


1  

One very important use-case I just stumbled across: dict.setdefault() is great for multi-threaded code when you only want a single canonical object (as opposed to multiple objects that happen to be equal).

我偶然发现的一个非常重要的用例是:dict.setdefault()对于多线程代码非常好,当您只想要一个单一的规范对象(而不是多个恰好相等的对象时)。

For example, the (Int)Flag Enum in Python 3.6.0 has a bug: if multiple threads are competing for a composite (Int)Flag member, there may end up being more than one:

例如,Python 3.6.0中的(Int)标志枚举有一个错误:如果多个线程争用一个复合(Int)标志成员,那么可能会出现多个线程:

from enum import IntFlag, auto
import threading

class TestFlag(IntFlag):
    one = auto()
    two = auto()
    three = auto()
    four = auto()
    five = auto()
    six = auto()
    seven = auto()
    eight = auto()

    def __eq__(self, other):
        return self is other

    def __hash__(self):
        return hash(self.value)

seen = set()

class cycle_enum(threading.Thread):
    def run(self):
        for i in range(256):
            seen.add(TestFlag(i))

threads = []
for i in range(8):
    threads.append(cycle_enum())

for t in threads:
    t.start()

for t in threads:
    t.join()

len(seen)
# 272  (should be 256)

The solution is to use setdefault() as the last step of saving the computed composite member -- if another has already been saved then it is used instead of the new one, guaranteeing unique Enum members.

解决方案是使用setdefault()作为保存计算组合成员的最后一步——如果已经保存了另一个成员,则使用setdefault()来代替新成员,以保证唯一的Enum成员。

#12


0  

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

[编辑]非常错误!setdefault总是会触发long_计算,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))

#13


0  

When the required default value is not always the same, or it's only desired for specific keys but it's preferred not to have one for others, one might consider using setdefault:

当所需的默认值不总是相同的时候,或者只需要特定的键值,但不希望为其他键使用时,可以考虑使用setdefault:

d = {}
...
# `i` should default to zero
i = d.setdefault(key, 0)
...
# `s` should default to an empty string
s = d.setdefault(key, '')
...

 

 

d = {}
...
# v should always default to a list
v = d.setdefault(key, [])
...
try:
    # EAFP, but I need the dict to raise a KeyError if the key is not found.
    w = d[k2]
except KeyError:
    ...
...

#14


0  

I like the answer given here:

我喜欢这里给出的答案:

http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html

http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html

In short, the decision (in non-performance-critical apps) should be made on the basis of how you want to handle lookup of empty keys downstream (viz. KeyError versus default value).

简而言之,这一决定(在非性能关键的应用程序中)应该基于你想要如何处理下游的空键(viz. KeyError与默认值)。

#15


0  

The different use case for setdefault() is when you don't want to overwrite the value of an already set key. defaultdict overwrites, while setdefault() does not. For nested dictionaries it is more often the case that you want to set a default only if the key is not set yet, because you don't want to remove the present sub dictionary. This is when you use setdefault().

setdefault()的不同用例是当您不想覆盖已设置的密钥的值时。defaultdict重写,而setdefault()则没有。对于嵌套字典,通常情况下,只有当键尚未设置时,您才想设置默认值,因为您不想删除当前的子字典。这是使用setdefault()的时候。

Example with defaultdict:

与defaultdict示例:

>>> from collection import defaultdict()
>>> foo = defaultdict()
>>> foo['a'] = 4
>>> foo['a'] = 2
>>> print(foo)
defaultdict(None, {'a': 2})

setdefault doesn't overwrite:

setdefault不覆盖:

>>> bar = dict()
>>> bar.setdefault('a', 4)
>>> bar.setdefault('a', 2)
>>> print(bar)
{'a': 4}