在Python列表推导中缓存值

5 投票
5 回答
2055 浏览
提问于 2025-04-15 12:08

我正在使用下面这种列表推导式:

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]

撰写回答