在尝试使用列表推导来制作给定条件的列表时,我看到以下内容:
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急切地评估列表推导吗?或者懒惰/急切的二分法与此完全无关?
答案 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
包含先前列表理解评估的结果,它不会因为更新用于计算的变量而神奇地更新。