在Python列表推导中缓存值
我正在使用下面这种列表推导式:
resources = [obj.get("file") for obj in iterator if obj.get("file") != None]
有没有办法在if语句中“缓存”一下obj.get("file")
的值,这样在生成返回列表的时候就不需要再对obj调用一次get
了?
5 个回答
1
创建一个临时的字典来存放值。然后,写一个函数,这个函数用这个字典作为缓存,在列表推导式中使用这个函数,像这样:
obj_cache = {}
def cache_get (target, key):
if (target, key) not in obj_cache: obj_cache[(target, key)] = target.get(key)
return obj_cache[(target, key)]
resources = [cache_get(obj, "file") for obj in iterator if cache_get(obj, "file") != None]
另外,你可能已经知道这一点(如果知道了,可以忽略这个回答),但是除非 obj.get("file") 是在进行数据库查询、打开文件、发起网络请求,或者做其他可能耗费资源的操作,否则在每次循环中调用它两次而不是一次,可能不会有什么大问题,因为这样只会增加 O(n) 的开销。
10
resources = filter(None, (obj.get("file") for obj in iterator))
查看filter的文档,了解如何提供你自己的评估函数。如果把None
作为函数传入(就像上面那样),那么会过滤掉所有不为真的值。
如果obj.get()返回的对象有一个奇怪的__nonzero__
方法,那么你需要传入lambda obj: obj != None
,这样才能得到和你原来的代码完全一样的结果。
5
如果你想继续使用列表或迭代器的简洁写法,而不是用 filter
函数,你可以简单地这样做:
resources = [file_obj
for file_obj in (obj.get("file") for obj in iterator)
if file_obj is not None]