5

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

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

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

4

5 回答 5

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

有关如何提供您自己的评估功能的信息,请参阅过滤器文档。传递None函数(如上)过滤掉所有不正确的值。

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

于 2009-06-09T19:01:36.947 回答
5

如果您想保留列表/迭代器推导而不是使用filter,您可以简单地使用:

resources = [file_obj
             for file_obj in (obj.get("file") for obj in iterator)
             if file_obj is not None]
于 2009-06-09T20:12:22.543 回答
1

尝试这样的事情:

resources = filter( lambda x: x is not None, [obj.get("file") for ob jin iterator])
于 2009-06-09T19:02:58.097 回答
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) 添加到您的成本中。

于 2009-06-09T19:20:55.817 回答
-1

从 Python 3.8 开始,可以使用赋值表达式来避免调用函数两次:

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']
于 2020-12-04T10:03:59.380 回答