You, sir, have misunderstood list comprehensions.
What you probably wanted (in words)
I want to remove all project ids that are invalid.
What you wrote
project_keys = [project_keys.remove(project.proj_id)
for project in projects.itervalues() if project.invalid]
What is actually going on
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
What is actually going on (now with more "functional")
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()))
As you can see, list comprehensions are not syntactical sugar around for
loops. Rather, list comprehensions are syntactical sugar around map()
and filter()
: apply a function to all items in a sequence that match a condition and get a list of results in return.
Here, by function it is actually meant a side-effect-free transformation of input into output. This means that you "cannot" use methods that change the input itself, like list.sort()
; you'll have to use their functional equivalents, like sorted()
.
By "cannot", however, I don't mean you'll get error messages or nasal demons; I mean you are abusing the language. In your case, the evaluation of the list comprehension that happens as you assign it to a variable does indeed produce the intended side-effects -- but does it produce them on the intended variables?
See, the only reason why this can execute without an error is that before this list comprehension, there was another list called project_keys
and it's that list you are actually changing!
Lists comprehensions are a result of functional programming, which rejects side effects. Keep that in mind when using lists comprehensions.
So here's a thought process you can use to actually get the list comprehension you wanted.
What you actually wanted (in words)
I want all project ids that are valid (= not invalid.)
What you actually wanted
dummy = []
for project in projects.itervalues():
if not project.invalid:
dummy.append(project.proj_id)
project_keys = dummy
del dummy
What you actually wanted (now with more functional)
mapped-fun = lambda project: project.proj_id
filtering-fun = lambda project: not project.invalid
project_keys = map(mapped-fun, filter(filtering-fun, projects.itervalues()))
What you actually wanted (now as a list comprehension)
project_keys = [project.proj_id for project in projects.itervalues()
if not project.invalid]