在Python列表推导中缓存值

时间:2009-06-09 18:57:40

标签: python list-comprehension

我正在使用以下列表理解:

resources = [obj.get("file") for obj in iterator if obj.get("file") != None]

有没有办法在if语句中检查obj.get("file")时“缓存”它,以便在生成返回列表时不必再在obj上调用get

5 个答案:

答案 0 :(得分:9)

resources = filter(None, (obj.get("file") for obj in iterator))

请参阅filter的文档,了解如何提供自己的评估功能。为函数传递None(如上所述)会过滤掉所有不正确的值。

如果obj.get()返回一个具有奇怪__nonzero__方法的对象,那么您需要传递lambda obj: obj != None以获得与原始代码完全相同的结果。

答案 1 :(得分:6)

如果你想继续使用列表/迭代器理解而不是使用filter,你可以简单地使用:

resources = [file_obj
             for file_obj in (obj.get("file") for obj in iterator)
             if file_obj is not None]

答案 2 :(得分:1)

尝试这样的事情:

resources = filter( lambda x: x is not None, [obj.get("file") for ob jin iterator])

答案 3 :(得分:1)

创建一个临时字典以保存值。然后,创建一个使用此dict作为缓存的函数,并在列表推导中使用该函数,如下所示:

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)。

答案 4 :(得分:0)

从Python 3.8开始,可以使用assignment expression避免两次调用该函数:

iterator = [{'file': 'abc'}, 
            {'file': None}, 
            {'file': 'def'}, 
            {'file': None}]
res = [file for obj in iterator 
       if (file := obj.get("file")) is not None]
print(res)
# ['abc', 'def']