使用列表和字典存储临时信息
我会有很多相似的对象,它们的参数也差不多。比如,一个对象的参数可能包括:
名字、布尔值、数字和列表。
这些对象的名字必须是唯一的,也就是说,不能有两个对象的名字是一样的。而布尔值、数字和列表的值可以重复。
我想我可以把这些数据存储为一个字典的列表,像这样:
list = [
{'name':'a', 'bool':true, 'number':123, 'list':[1, 2, 3]},
{'name':'b', 'bool':false, 'number':143, 'list':[1, 3, 5]},
{'name':'c', 'bool':false, 'number':123, 'list':[1, 4, 5, 18]},
]
在我创建另一个字典之前,检查这个唯一名字是否已经存在于字典列表中,最快的方法是什么?我是不是需要遍历这个列表,检查每个字典里的名字?在处理这些信息时,什么方法既快又能节省内存?假设可能会有不同的相似列表同时在不同的线程或任务中处理,而且每个列表的大小可能在100到100,000个字典之间。我应该把这些列表存储在数据库里,而不是内存中吗?
我明白,也许在项目还没做好之前,不应该过于考虑优化(存储信息和线程),所以请先回答关于唯一名字查找的问题 :)
谢谢,
Alan
5 个回答
如果你不想改变现有的数据结构,可以使用下面的方法。否则,可以参考poke的回答。
>>> my_list = [
... {'name':'a', 'bool':True, 'number':123, 'list':[1, 2, 3]},
... {'name':'b', 'bool':False, 'number':143, 'list':[1, 3, 5]},
... {'name':'c', 'bool':False, 'number':123, 'list':[1, 4, 5, 18]},
... ]
>>> def is_present(data, name):
... return any(name == d["name"] for d in data)
...
>>> is_present(my_list, "a")
True
>>> is_present(my_list, "b")
True
>>> is_present(my_list, "c")
True
>>> is_present(my_list, "d")
False
当你把一个可迭代对象传给any时,如果里面有任何一个元素是True,它就会返回True。
(name == d["name"] for d in data)
这个表达式会创建一个生成器。每当有人(在这里是any
)请求下一个元素时,它就会从data
中获取下一个元素d
,然后通过表达式name == d["name"]
进行转换。因为生成器是懒惰的,也就是说,只有在请求下一个元素时才会进行转换,所以这样做会占用相对较少的内存(而且无论列表的大小如何,所占用的内存量都是一样的)。
一旦你开始使用字典而不是列表,检查你想要的内容的最快方法是:
if 'newkey' not in items:
# create a new record
因为你希望能够从多个线程访问这些记录,所以我建议你保持一个锁的集合。顺便说一下,这种设计应该在一开始就考虑,因为它是应用程序设计的一部分,而不是优化的一部分。
class DictLock(dict):
def __init__(self):
self._lock = threading.Lock()
def __getitem__(self, key):
# lock to prevent two threads trying to create the same
# entry at the same time. Then they would get different locks and
# both think that they could access the key guarded by that lock
with self._lock:
if key not in self.iterkeys():
self[key] = threading.Lock()
return super(DictLock, self).__getitem__(key)
现在,如果你想修改你的项目,可以使用这些锁来确保安全。
locks = DictLock()
with locks['a']:
# modify a.
或者用来插入一个新元素
with locks['z']:
#we are now the only ones (playing by the rules) accessing the 'z' key
items['z'] = create_new_item()
如果名字是每个内部数据的唯一标识符,你也可以把外部数据用字典来表示:
data = {
'a' : { 'bool':true, 'number':123, 'list':[1, 2, 3] },
'b' : { 'bool':false, 'number':143, 'list':[1, 3, 5] },
'c' : { 'bool':false, 'number':123, 'list':[1, 4, 5, 18] },
}
这样你就可以很方便地检查某个键是否存在。
顺便提一下,不要把你的变量命名为 list
或 dict
,因为这样会覆盖掉 Python 内置的对象。