在python中评估列表推导

时间:2013-09-18 22:30:58

标签: python lazy-evaluation

在尝试使用列表推导来制作给定条件的列表时,我看到以下内容:

In [1]: mydicts = [{'foo':'val1'},{'foo':''}]

In [2]: mylist = [d for d in mydicts if d['foo']]

In [3]: mylist
Out[3]: [{'foo': 'val1'}]

In [4]: mydicts[1]['foo'] = 'val2'

In [5]: mydicts
Out[5]: [{'foo': 'val1'}, {'foo': 'val2'}]

In [6]: mylist
Out[6]: [{'foo': 'val1'}]

我一直在阅读文档以尝试理解这一点,但到目前为止还没有提出任何建议,所以我在这里问我的问题:为什么mylist从不包含{{ 1}}即使列表理解中的引用指向{'foo': 'val2'}mydict包含In [6]?这是因为Python急切地评估列表推导吗?或者懒惰/急切的二分法与此完全无关?

3 个答案:

答案 0 :(得分:4)

Python中没有对列表进行惰性评估。列表推导只是创建一个新列表。如果你想要"懒惰"评估,改为使用generator expression

my_generator_expression = (d for d in mydicts if d['foo']) # note parentheses
mydicts[1]['foo'] = 'val2'
print(my_generator_expression) # >>> <generator object <genexpr> at 0x00000000>
for d in my_generator_expression:
    print(d) # >>> {'foo': 'val1'}
             # >>> {'foo': 'val2'}

请注意,生成器在几个重要方面与列表不同。也许最值得注意的是,一旦你对它们进行迭代,它们就会筋疲力尽,所以如果你只需要它们包含一次的数据,它们最好用。

答案 1 :(得分:3)

我认为你对列表理解的作用有点困惑。

执行此操作时:

[d for d in mydicts if d['foo']]

评估为新列表。所以,当你这样做时:

mylist = [d for d in mydicts if d['foo']]

您将该列表指定为mylist的值。你可以很容易地看到这一点:

assert type(mylist) == list

您没有指定每次mylist重新评估的“列表理解”。 Python中没有任何魔术值可以每次重新评估。 (你可以伪造它们,例如,用class创建一个@property,但这不是一个例外;它是被重新评估的表达式myobj.myprop,不是myprop本身。)


事实上,mylist = [d for d in mydicts if d['foo']]基本相同mylist = [1, 2, 3]。*在这两种情况下,您都要创建一个新列表,并将其分配给mylist。您不希望第二个每次都重新评估[1, 2, 3](否则,mylist[0] = 0执行效果不会很好,因为只要您尝试查看mylist''得到一个新的,原始的名单!)。这里也是如此。

*在Python 3.x中,它们不只是基本上相同;它们只是不同类型的列表显示。在2.x中,它更加模糊,而且它们恰好都会评估新的列表对象。

答案 2 :(得分:0)

mylist包含先前列表理解评估的结果,它不会因为更新用于计算的变量而神奇地更新。