为什么这个列表理解不能做我期望它做的事情?

时间:2010-05-30 19:53:09

标签: python list-comprehension

原始列表project_keys = sorted(projects.keys())[101, 102, 103, 104, 105, 106, 107, 108, 109, 110],其中以下项目今年被视为invalid:108,109,110。

因此:

for project in projects.itervalues():
# The projects dictionary is mapped to the Project class
    if project.invalid:
    # Where invalid is a Bool parameter in the Project class
     project_keys.remove(project.proj_id)  

print project_keys

这将返回一个整数列表(项目ID为):

[101, 102, 103, 104, 105, 106, 107]

甜。

现在,我希望它使用列表推导尝试相同的事情。

project_keys = [project_keys.remove(project.proj_id) for project in projects.itervalues() if project.invalid  

print project_keys

返回:

[None, None, None]

所以我填充的列表与删除的元素的编号相同,但它们是None的?

有人可以指出我做错了吗?

另外,为什么我会在顶部的for-if块上使用列表推导?简明?看起来更好吗?

2 个答案:

答案 0 :(得分:6)

您的列表理解使用副作用。只是执行它应该更新project_keys以给出你想要的结果。

[project_keys.remove(project.proj_id)
 for project in projects.itervalues()
 if project.invalid]

remove的返回值为None。将列表理解的结果分配给project_keys是您出错的地方。

尽管如此,一个简单的循环可能更清晰。使用副作用的列表理解可能会令人困惑。

但是,您可以稍微不同的方式解决问题:

project_keys = sorted(project.proj_id
                      for project in projects.itervalues()
                      if not project.invalid)

这可以保留您感兴趣的项目,而不是删除那些您不感兴趣的项目。我上面给出的示例使用生成器表达式而不是列表推导,但它可以使用。

答案 1 :(得分:4)

先生,您误解了列表理解。

你可能想要的(用文字表示)

  

我想删除所有无效的项目ID。

你写的是什么

project_keys = [project_keys.remove(project.proj_id)
                for project in projects.itervalues() if project.invalid]

究竟发生了什么

dummy = []
for project in projects.itervalues():
  if project.invalid:
    dummy.append(project_keys.remove(project.proj_id)) #what are you
project_keys = dummy                                   #removing items from?
del dummy                                            

实际发生了什么(现在有更多“功能性”)

mapped-fun = lambda project: project_keys.remove(project.proj_id)
filtering-fun = lambda project: project.invalid
project_keys = map(mapped-fun, filter(filtering-fun, projects.itervalues()))

正如您所看到的,列表推导是围绕for循环的语法糖。相反,列表推导是围绕map()filter() 的语法糖:将函数应用于符合条件的序列中的所有项目并获取返回列出结果。

在这里,通过功能,它实际上是指输入到输出的无副作用转换。这意味着您“无法”使用更改输入本身的方法,例如list.sort();你必须使用它们的功能等价物,比如sorted()

但是,“不能”,我并不是说你会得到错误信息或nasal demons;我的意思是你在滥用这种语言。在你的情况下,当你将它分配给变量时对列表理解的评估确实会产生预期的副作用 - 但它是否会在预期的变量上产生它们?

请参阅,唯一可以在没有错误的情况下执行的原因是,在此列表理解之前,有另一个名为project_keys列表,而 列表你实际上在改变!

列表理解是函数式编程的结果,它拒绝副作用。使用列表推导时请记住这一点。


所以这是一个思考过程,你可以用来实际获得你想要的列表理解。

你真正想要的(用文字表示)

  

我想要所有有效的项目ID(=无效。)

你真正想要的是什么

dummy = []
for project in projects.itervalues():
  if not project.invalid:
    dummy.append(project.proj_id)
project_keys = dummy
del dummy

你真正想要的东西(现在功能更强大)

mapped-fun = lambda project: project.proj_id
filtering-fun = lambda project: not project.invalid
project_keys = map(mapped-fun, filter(filtering-fun, projects.itervalues()))

你真正想要的东西(现在作为列表理解)

project_keys = [project.proj_id for project in projects.itervalues()
                if not project.invalid]