为什么列表字典中的赋值会影响字典中的所有列表?

问题描述 投票:6回答:3

我正在尝试根据字符串中存在的1来将某些数字的二进制字符串分组在一起。

这不起作用:

s = "0 1 3 7 8 9 11 15"
numbers = map(int, s.split())
binaries = [bin(x)[2:].rjust(4, '0') for x in numbers]

one_groups = dict.fromkeys(range(5), [])
for x in binaries:
    one_groups[x.count('1')] += [x]

预期字典one_groups必须为

{0: ['0000'], 
 1: ['0001', '1000'], 
 2: ['0011', '1001'], 
 3: ['0111', '1011'], 
 4: ['1111']}

但是我知道

{0: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'], 
 1: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'], 
 2: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'], 
 3: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'], 
 4: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111']}

到目前为止,唯一起作用的是如果我使用one_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]而不是one_groups[x.count('1')] += [x]

但是为什么会这样呢?如果我没记错的话,dict[key]是否不应该返回该字典的值,类似于dict.get(key)的工作方式?我已经看到了该线程Why dict.get(key) instead of dict[key]?,但是对于这种特殊情况,它没有回答我的问题,因为我确定该程序并不是要获取KeyError

我也尝试过one_groups[x.count('1')].append(x),但这也不起作用。

python dictionary mutable
3个回答
11
投票

问题是可变性:

one_groups = dict.fromkeys(range(5), [])-这会将与值相同的数组传递给所有键。因此,如果更改一个值,则全部更改。

基本上与说相同:

tmp = []
one_groups = dict.fromkeys(range(5), tmp)
del tmp

如果要使用新列表,则需要循环执行-显式for循环或dict理解:

one_groups = {key: [] for key in range(5)}

此事物将为每个键“执行” [](等于list()),从而使值具有不同的列表。


get为什么起作用?因为您显式获取了当前列表,但是+创建了新的结果列表。 one_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]one_groups[x.count('1')] = one_groups[x.count('1')] + [x]都没关系-重要的是+

[我知道每个人都说a+=b只是a=a+b,但是优化的实现可能有所不同-在列表的情况下,+=只是.append,因为我们知道我们希望将结果保存在当前变量中,因此创建新列表将浪费内存。


5
投票

问题在使用one_groups = dict.fromkeys(range(5), [])

您可以改用它:one_groups = {i:[] for i in range(5)}


0
投票

这是dict的fromkeys方法的帮助。

关于内置功能fromkeys的帮助:

buildins.type实例的

fromkeys(iterable,value = None,/)方法使用可迭代键并将值设置为value创建一个新字典

这表示fromkeys会接受一个值,即使它是可调用的,它也会先对其求值,然后将该值分配给所有dict键。

列表在Python中是可变的,因此它将分配相同的空列表引用,并且一项更改将影响所有列表。

改为使用defaultdict:

>>> from collections import defaultdict
>>> one_groups = defaultdict(list)
>>> for x in binaries:
      one_groups[x.count('1')] += [x]
>>> one_groups = dict(one_groups) # to stop default dict behavior

这将接受对不存在的键的分配,并且值将默认为空列表(在这种情况下)。

© www.soinside.com 2019 - 2024. All rights reserved.