参考dicts列表

时间:2016-05-12 03:49:07

标签: list python-2.7 dictionary

Mint Cinnamon上的Python 2.7 17.3。 我有一些测试代码采用了一系列的dicts,尽管经历了几个小时的挫折,我似乎无法弄清楚为什么它不能正常工作。

blockagedict = {'location': None, 'timestamp': None, 'blocked': None}
blockedlist = [blockagedict]

blockagedict['location'] = 'A'
blockagedict['timestamp'] = '12-Apr-2016 01:01:08.702149'
blockagedict['blocked'] = True

blockagedict['location'] = 'B'
blockagedict['timestamp'] = '12-Apr-2016 01:01:09.312459'
blockagedict['blocked'] = False
blockedlist.append(blockagedict)

for test in blockedlist:
    print test['location'], test['timestamp'], test['blocked']

这总是产生以下输出,我无法弄清楚为什么,也看不出我的代码是否有任何问题。它总是打印出最后一组dict值,但是如果我没有弄错的话,应该打印全部。

B 12-Apr-2016 01:01:09.312459 False
B 12-Apr-2016 01:01:09.312459 False

我很高兴有人向我展示我的方式的错误,并让我摆脱痛苦。

3 个答案:

答案 0 :(得分:4)

这是因为行blockedlist = [blockagedict]实际上在列表中存储了对dict的引用,而不是副本。您的代码有效地创建了一个列表,该列表具有对同一对象的两个引用。

答案 1 :(得分:1)

如果您关心性能并且列表中有100万个字典,所有字典都使用相同的键,那么最好使用NumPy结构化数组。然后,您可以拥有一个单一,高效的数据结构,该结构基本上是行的矩阵和适当类型的命名列。您在评论中提到您可能事先知道行数。这里是使用NumPy重写你的示例代码,它将比一百万个dicts的列表更加高效。

import numpy as np

dtype = [('location', str, 1), ('timestamp', str, 27), ('blocked', bool)]

count = 2 # will be much larger in the real program

blockages = np.empty(count, dtype) # use zeros() instead if some data may never be populated

blockages[0]['location'] = 'A'
blockages[0]['timestamp'] = '12-Apr-2016 01:01:08.702149'
blockages[0]['blocked'] = True

blockages['location'][1] = 'B' # n.b. indexing works this way too
blockages['timestamp'][1] = '12-Apr-2016 01:01:09.312459'
blockages['blocked'][1] = False

for test in blockages:
    print test['location'], test['timestamp'], test['blocked']

请注意,使用情况几乎相同。但是存储是固定大小的单一分配。这将减少内存使用量和计算时间。

作为一个很好的副作用,如上所述,完全回避你最初的问题,多次引用同一行。现在所有数据都直接放入矩阵中,根本没有对象引用。

稍后您在评论中提到您无法使用NumPy,因为它可能未安装。好吧,我们仍然可以避免不必要的决定,例如:

from array import array

blockages = {'location': [], 'timestamp': [], 'blocked': array('B')}

blockages['location'].append('A')
blockages['timestamp'].append('12-Apr-2016 01:01:08.702149')
blockages['blocked'].append(True)

blockages['location'].append('B')
blockages['timestamp'].append('12-Apr-2016 01:01:09.312459')
blockages['blocked'].append(False)

for location, timestamp, blocked in zip(*blockages.values()):
    print location, timestamp, blocked

注意我在这里使用array来有效存储固定大小的blocked值(这样每个值只需要一个字节)。

您仍然可以避免使用可调整大小的列表,但至少您不需要在列表的每个插槽中存储dict。这应该更有效率。

答案 2 :(得分:0)

好的,我已经初步确定了蝙蝠的名单,这似乎有效。虽然我很想为此写一堂课。

blockedlist = [{'location': None, 'timestamp': None, 'blocked': None} for k in range(2)]

blockedlist[0]['location'] = 'A'
blockedlist[0]['timestamp'] = '12-Apr-2016 01:01:08.702149'
blockedlist[0]['blocked'] = True

blockedlist[1]['location'] = 'B'
blockedlist[1]['timestamp'] = '12-Apr-2016 01:01:09.312459'
blockedlist[1]['blocked'] = False

for test in blockedlist:
    print test['location'], test['timestamp'], test['blocked']

这就产生了我想要的东西:

A 12-Apr-2016 01:01:08.702149 True
B 12-Apr-2016 01:01:09.312459 False

我将从一个包含1到2百万行的文本文件中读取,因此转换代码以迭代这些行不会成为问题。