1

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

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从不包含{'foo': 'val2'},即使列表理解中的引用指向mydict,其中In [6]包含{'foo': 'val2'}? 这是因为 Python 急切地评估列表推导吗?还是懒惰/渴望二分法与此完全无关?

4

3 回答 3

7

Python 中没有对列表的惰性求值。列表推导式只是创建一个新列表。如果您想要“惰性”评估,请改用生成器表达式

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'}

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

于 2013-09-18T22:36:04.857 回答
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 中没有每次都会重新评估的神奇值。(您可以通过例如用 a创建 a来伪造它们,但这并不是真正的例外;它是被重新评估的表达式,而不是它本身。)class@propertymyobj.mypropmyprop


事实上,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 中,它有点模糊,它们只是碰巧都对新的列表对象求值。

于 2013-09-18T22:36:32.373 回答
0

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

于 2013-09-18T22:35:53.443 回答