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

2024-12-12 08:41:00
admin
原创
179
摘要:问题描述:我尝试以编程方式创建列表字典,但无法单独处理字典键。每当我创建列表字典并尝试附加到一个键时,所有键都会更新。这是一个非常简单的测试用例:data = {} data = data.fromkeys(range(2),[]) data[1].append('hello') print data 实际结...

问题描述:

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

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方法没有按预期发挥作用?


解决方案 1:

[]作为第二个参数传递给时dict.fromkeys(),结果中的所有值dict将是同一个 list对象。

在 Python 2.7 或更高版本中,请改用字典推导式:

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

在早期版本的 Python 中,没有字典推导式,但可以将列表推导式传递给dict构造函数:

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

在 2.4-2.6 中,还可以将生成器表达式传递给,并且可以删除dict周围的括号:

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

解决方案 2:

尝试使用defaultdict代替:

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

这样,键就不需要提前用空列表初始化。defaultdict()每次访问尚不存在的键时,对象都会调用给它的工厂函数。因此,在此示例中,尝试访问data[1]data[1] = list()在内部触发,为该键提供一个新的空列表作为其值。

原始代码.fromkeys共享一个(可变)列表。同样,

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

将输出{0: [1, 2], 1: [1, 2]}。文档中提到了dict.fromkeys()这一点:

所有值都仅引用单个实例,因此通常是可变对象(例如空列表)是没有意义的。

另一种选择是使用dict.setdefault()方法,该方法首先检查键是否存在,如果不存在则设置默认值,然后检索键的值。.append然后可以在结果上调用:

data = {}
data.setdefault(1, []).append('hello')

最后,要从已知键列表和给定的“模板”列表创建字典(其中每个值应该以相同的元素开头,但是是一个不同的列表),请使用字典理解并复制初始列表:

alist = [1]
data = {key: alist[:] for key in range(2)}

这里,alist[:]创建了 的浅拷贝alist,并且对每个值分别执行此操作。有关复制列表的更多技术,请参阅如何克隆列表以使其在分配后不会意外更改?

解决方案 3:

您可以使用字典理解:

>>> keys = ['a','b','c']
>>> value = [0, 0]
>>> {key: list(value) for key in keys}
    {'a': [0, 0], 'b': [0, 0], 'c': [0, 0]}

解决方案 4:

dict这个答案是为了向那些对尝试使用fromkeys()可变默认值实例化所得到的结果感到困惑的人解释这种行为dict

考虑:

#Python 3.4.3 (default, Nov 17 2016, 01:08:31) 

# start by validating that different variables pointing to an
# empty mutable are indeed different references.
>>> l1 = []
>>> l2 = []
>>> id(l1)
140150323815176
>>> id(l2)
140150324024968

因此对 的任何更改都l1不会影响l2,反之亦然。这对于迄今为止的任何可变因素都是正确的,包括dict

# create a new dict from an iterable of keys
>>> dict1 = dict.fromkeys(['a', 'b', 'c'], [])
>>> dict1
{'c': [], 'b': [], 'a': []}

这是一个方便的功能。这里我们为每个键分配一个默认值,该默认值恰好是一个空列表。

# the dict has its own id.
>>> id(dict1)
140150327601160

# but look at the ids of the values.
>>> id(dict1['a'])
140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328

事实上,它们都使用相同的引用!更改一个引用就意味着更改所有引用,因为它们实际上是同一个对象!

>>> dict1['a'].append('apples')
>>> dict1
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}
>>> id(dict1['a'])
>>> 140150323816328
>>> id(dict1['b'])
140150323816328
>>> id(dict1['c'])
140150323816328

对于许多人来说,这并不是预期的结果!

现在让我们尝试对用作默认值的列表进行明确的复制。

>>> empty_list = []
>>> id(empty_list)
140150324169864

现在用 的副本创建一个字典empty_list

>>> dict2 = dict.fromkeys(['a', 'b', 'c'], empty_list[:])
>>> id(dict2)
140150323831432
>>> id(dict2['a'])
140150327184328
>>> id(dict2['b'])
140150327184328
>>> id(dict2['c'])
140150327184328
>>> dict2['a'].append('apples')
>>> dict2
{'c': ['apples'], 'b': ['apples'], 'a': ['apples']}

还是没有结果!我听到有人喊,这是因为我用了一个空列表!

>>> not_empty_list = [0]
>>> dict3 = dict.fromkeys(['a', 'b', 'c'], not_empty_list[:])
>>> dict3
{'c': [0], 'b': [0], 'a': [0]}
>>> dict3['a'].append('apples')
>>> dict3
{'c': [0, 'apples'], 'b': [0, 'apples'], 'a': [0, 'apples']}

的默认行为fromkeys()是分配None给该值。

>>> dict4 = dict.fromkeys(['a', 'b', 'c'])
>>> dict4
{'c': None, 'b': None, 'a': None}
>>> id(dict4['a'])
9901984
>>> id(dict4['b'])
9901984
>>> id(dict4['c'])
9901984

确实,所有值都是相同的(而且是唯一的!)None。现在,让我们以无数种方式之一迭代dict并更改值。

>>> for k, _ in dict4.items():
...    dict4[k] = []

>>> dict4
{'c': [], 'b': [], 'a': []}

嗯。看起来和以前一样!

>>> id(dict4['a'])
140150318876488
>>> id(dict4['b'])
140150324122824
>>> id(dict4['c'])
140150294277576
>>> dict4['a'].append('apples')
>>> dict4
>>> {'c': [], 'b': [], 'a': ['apples']}

但它们确实是不同的[],在这种情况下这是预期的结果。

解决方案 5:

你可以使用这个:

l = ['a', 'b', 'c']
d = dict((k, [0, 0]) for k in l)

解决方案 6:

您正在用对单个列表的引用填充您的字典,因此当您更新它时,更新将反映在所有引用中。请尝试使用字典推导式。请参阅
在 Python 中使用列表推导式创建字典

d = {k : v for k in blah blah blah}
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用