5

Possible Duplicate:
Is it Pythonic to use list comprehensions for just side effects?
proper use of list comprehensions - python

Python has the useful and elegant list comprehension syntax. However AFAIK it always produces a list. Sometimes I feel the urge to use list comprehension just for its compactness and elegance without needing the resulting list:

[some_func(x) for x in some_list if x>5]

some_func() may return something which I don't need, it may not return anything at all. I tried the generator syntax:

(some_func(x) for x in some_list if x>5)

but as you may guess, it doesn't iterate over some_list. It does so only within certain context:

other_func(some_func(x) for x in some_list if x>5)

So... is there a syntax I'm missing to get this to work, or should I always fall back to 3 lines?

for x in some_list:
    if x>5:
        some_func(x)
Community
  • 1
  • 1
Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359
  • 3
    There is a legitimate and distinct question here, "How do I run an iterator to completion without creating a throw-away list". – Raymond Hettinger Jan 02 '12 at 07:14
  • @RaymondHettinger is right, I'm looking for an alternative for a construct without knowing its name or if it exists. This is quite different than the other two linked questions – Jonathan Livni Jan 02 '12 at 07:40
  • @IgnacioVazquez-Abrams,@delnan - I also changed the question's name to reflect this – Jonathan Livni Jan 02 '12 at 07:47

4 Answers4

10

I don't now if you will find it elegant, but there is a consume recipe in the itertools docs that is very fast and will run an iterator to completion without building-up a list:

>>> consume(some_func(x) for x in some_list if x>5)
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • I never imagined that you'd be able to create a zero-length `deque` or, even if you could, that it would be useful for anything. – kindall Jan 09 '12 at 17:15
3

Use a genex to get the appropriate values to iterate over.

for i in (x for x in some_list if x > 5):
    some_func(i)
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • @RaymondHettinger - I'd disagree it's awful (in fact: +1). I contrarily find it quite pythonic, in that it uses both a `for` loop and a generator for what they are meant in a compact and self-explanatory way... care to clarify why you don't like it? – mac Jan 02 '12 at 07:31
2

If the some_func() doesn't return a value (i.e. returns None):

any(some_func(x) for x in some_list if x > 5)

is a possibility.

Otherwise you can do:

any(some_func(x) and False for x in some_list if x > 5)

Or perhaps more readable (given the match with the plain-English meaning of all) is:

all(some_func(x) or True for x in some_list if x > 5)

I like the consume recipe that Raymond found better, though, as it doesn't force you to make the generator return some particular value to guarantee it's entirely consumed, and is going to be faster to boot.

kindall
  • 178,883
  • 35
  • 278
  • 309
0

Honestly, in my code I prefer to use the three line for expression, but I think that the one-liner you're looking for might be this one:

for x in some_list: func(x) if x>5 else None

Note: I tried to use pass instead of None, which I though would look a little bit better, but that throws a SyntaxError exception.

jcollado
  • 39,419
  • 8
  • 102
  • 133
  • 1
    You can only return objects (like `42` or `None`), not statements (like `pass`, `print` or `raise`). – mac Jan 02 '12 at 07:54