如何在Python中初始化空列表字典?


87

我以编程方式创建列表字典的尝试未能使我单独处理字典键。每当我创建列表字典并尝试将其追加到一个键时,所有这些键都会更新。这是一个非常简单的测试用例:

data = {}
data = data.fromkeys(range(2),[])
data[1].append('hello')
print data

实际结果: {0: ['hello'], 1: ['hello']}

预期结果: {0: [], 1: ['hello']}

这是有效的

data = {0:[],1:[]}
data[1].append('hello')
print data

实际和预期结果: {0: [], 1: ['hello']}

为什么该fromkeys方法无法按预期工作?

Answers:


110

[]作为第二个参数传递给dict.fromkeys()会产生相当无用的结果-字典中的所有值将是相同的列表对象。

在Python 2.7或更高版本中,您可以改用二元理解:

data = {k: [] for k in range(2)}

在早期版本的Python中,您可以使用

data = dict((k, []) for k in range(2))

3
好吧,这是相当不直观的行为,是否对所有键都使用同一对象的任何想法?
2016年

2
@Bar因为该函数在Python语言的语义范围内无能为力。您传入单个对象用作所有键的值,以便单个对象用于所有键。最好让该fromkeys()方法接受一个工厂函数,以便我们可以将其list作为一个函数传入,并且对于每个创建的键都将调用一次功能,但这不是的实际API dict.fromkeys()
Sven Marnach '16

3
这一点都不直观。我花了一个小时才找到。谢谢
Astrid

1
如果将dict()作为第二个参数传递,也会发生同样的事情。非常令人困惑的行为。
奥利

@Orly这是因为首先创建一个空字典,然后将对它的引用传递给所有初始化。
Dr_Zaszuś

82

改用defaultdict

from collections import defaultdict
data = defaultdict(list)
data[1].append('hello')

这样,您不必预先初始化要用于列表的所有键。

您的示例中发生的事情是您使用一个(可变)列表:

alist = [1]
data = dict.fromkeys(range(2), alist)
alist.append(2)
print data

将输出{0: [1, 2], 1: [1, 2]}


2
就我而言,我需要预先初始化所有键,以便其余程序逻辑可以按预期工作,但是否则,这将是一个很好的解决方案。谢谢。
Martin Burch

我猜想这个答案缺少的是,与OP相比,此解决方案有效,因为list这不是一个空列表,而是一个类型(我猜您可以将其视为可调用的构造函数)。因此,每次传递缺少的密钥时,都会创建一个新列表,而不是重复使用相同的列表。
Dr_Zaszuś

8

您将用对单个列表的引用来填充字典,因此在更新列表时,更新将反映在所有引用中。请尝试使用字典理解。请参阅 在Python中使用列表理解功能创建字典

d = {k : v for k in blah blah blah}

关于初始化字典值的好建议...谢谢cobie!我扩展了您的示例,以重置现有字典d中的值。我按如下方式执行此操作:d = {k在d中的k:0}
约翰·

什么是v这个答案吗?
Dr_Zaszuś

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.