我的一个项目中有一个情况,我可以使用列表或词典,我很难选择使用哪个。
我正在分析大量商品(> 400k)。我会有(> 400k)列表或词典,我会经常使用。 (获取/设置/更新)
在我的特殊情况下,如果我根本不考虑性能,使用字典感觉就像方便而不是列表。但是,我知道我可以使用列表管理同样的事情。
我是否应该寻求可读性并使用字典或使用字典可能会增加太多的开销,从内存和时间的角度来看,这会大大降低我的性能。
我知道这个问题有点过于宽泛。但是在我做完这个决定之后我开始构建我的所有逻辑之前,我想问它。
我的情况简而言之:
我有键0,1,...,n
的值。现在,密钥将始终是从0
到n
的整数,我可以将其保存在列表中。
但是,我可以想到将来可能出现的一些情况,我需要保留一些非整数键的项目。或者不是连续的整数。
所以,问题是如果首先使用字典而不是列表不会增加大部分内存/时间成本,我首先会使用字典。但是,我不确定是否有> 400k字典与> 400k列表在性能方面有很大差异。
答案 0 :(得分:5)
直接回答您的问题:词典的开销明显高于列表:
尽管Python词典的设计非常精确且速度惊人,但如果你有一个可以使用直接索引的算法,你将节省空间和时间。
然而,从您的问题和随后的讨论的声音,听起来您的需求可能会随着时间的推移而改变,并且您有一些不确定性(“但是,我可以想到将来可能出现的一些情况,我会需要保留一些非整数键的项目“)
如果是这种情况,我建议您创建自己的混合数据结构,以便随着需求的发展,您可以在隔离的地方解决存储效率,同时允许您的应用程序使用简单,可读的代码来存储和检索对象。
例如,这是一个名为maybelist
的Python3类,它是从列表派生的,但是检测是否存在非数字键,在字典中存储异常,同时为一些常见的列表操作提供映射:
class maybelist(list):
def __init__(self, *args):
super().__init__(*args)
self._extras = dict()
def __setitem__(self, index, val):
try:
super().__setitem__(index, val)
return
except TypeError:
# Index is not an integer, store in dict
self._extras[index] = val
return
except IndexError:
pass
distance = index - len(self)
if distance > 0:
# Put 'None' in empty slots if need be
self.extend((None,) * distance)
self.append(val)
def __getitem__(self, index):
try:
return super().__getitem__(index)
except TypeError:
return self._extras[index]
def __str__(self):
return str([item for item in self])
def __len__(self):
return super().__len__() + len(self._extras)
def __iter__(self):
for item in itertools.chain(super().__iter__(), self._extras):
yield item
所以,你可以像对待数组一样对待它,让它自动扩展:
>>> x = maybelist()
>>> x[0] = 'first'
>>> x[1] = 'second'
>>> x[10] = 'eleventh'
>>> print(x)
['first', 'second', None, None, None, None, None, None, None, None, 'eleventh']
>>> print(x[10])
eleventh
或者您可以添加带有非数字键的项目(如果它们存在):
>>> x['unexpected'] = 'something else'
>>> print(x['unexpected'])
something else
如果使用迭代器或您选择的其他方法访问它,该对象似乎表现得正常:
>>> print(x)
['first', 'second', None, None, None, None, None, None, None, None, 'eleventh', 'unexpected']
>>> print(len(x))
12
这只是一个示例,您需要定制这样的类以满足应用程序的需要。例如,结果对象的严格行为不像列表(例如,x[len(x)-1]
不是最后一项)。但是,您的应用程序可能不需要如此严格的遵守,如果您小心并且计划得当,您可以创建一个既提供高度优化的存储又为将来留出空间以满足不断变化的数据结构需求的对象。
答案 1 :(得分:2)
dict
使用的内存比list
多得多。如果计算机不是很忙,可能还不足以成为一个问题。当然也有例外 - 如果它是一台每秒100个连接的Web服务器,您可能需要考虑以牺牲可读性为代价来节省内存
>>> L = range(400000)
>>> sys.getsizeof(L)
3200072 # ~3 Megabytes
>>> D = dict(zip(range(400000), range(400000)))
>>> sys.getsizeof(D)
25166104 # ~25 Megabytes
答案 2 :(得分:1)
对于你不那么明确的问题,不完全是答案,但这是我的想法:
你说
我正在分析大量商品(> 400k)
在这种情况下,我建议您使用生成器和/或以块的形式处理日期。
更好的选择是将您的数据(键值对)放在Redis中,并一次取出它的数据块。 Redis可以非常轻松地处理您的数据量。
您可以编写一个一次处理一个块的脚本,并使用asyncio
模块,您可以并行化块处理。
这样的事情:
from concurrent import futures
def chunk_processor(data):
"""
Process your list data here
"""
pass
def parallelizer(map_func, your_data_list, n_workers=3):
with futures.ThreadPoolExecutor(max_workers=n_workers) as executor:
for result in executor.map(map_func, your_data_list):
# Do whatever with your result
# Do the take out chunks of your data from Redis here
chunk_of_list = get_next_chunk_from_redis()
# Your processing starts here
parallelizer(chunk_processor, your_data_list)
同样,可以做得更好,但我告诉你其中一个方法。
答案 3 :(得分:1)