3

The following is totally bogus code. But let's say you needed to do some extra side effecting function calls (for debugging to logs)? How would you put that in?

[ i for i in range(10) ]

Or does one always have to rewrite as a normal for loop?

list=[]
for i in range(10):
   otherStuff()
   list.append(i)

In C, there is a comma operator for such things...

Chris
  • 1,219
  • 2
  • 11
  • 21

3 Answers3

6

Plainly, don't use side-effects in list comprehensions. It makes your code incredibly unclear to the next person who has to maintain it, even if you understand it perfectly. List comprehensions are a succinct way of creating a list, not a way to call a function n times.

For further reading, see the question Is it Pythonic to use list comprehensions for just side effects?

In other words, you should use an explicit for loop for that.

Community
  • 1
  • 1
Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • 1
    @Chris programmer-time versus ease of use is a common trade off. Best practice is to use an explicit `for` loop. YMMV – Adam Smith Mar 31 '16 at 15:30
  • @Chris You want to debug list comprehension? Doesn't make much sense. Just print it afterwards. – freakish Mar 31 '16 at 15:34
3

You need to include a call to your side-effect-having code somewhere in your value expression, but you need to ignore that value.

or is one possible choice for this. Just make sure that your side-effect function returns a "Falsey" value (False, None, 0, etc.), and put your debug call in the left-hand side of the or.

def debug_func(i):
    print i, i**3
    return None
whole_numbers = [ debug_func(i) or i for i in range(10) ]
print whole_numbers

As an alternative, your function could be an identity function, always returning its sole argument:

def debug_func(i):
    print i, i**3
    return i

# Production code:
whole_numbers = [i for i in range(10)]

# Debug code
whole_numbers = [debug_func(i) for i in range(10)]
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • 2
    Ps. I agree with others. Don't do this. But you didn't ask **if** you should do it, you asked **how** you could do it. – Robᵩ Mar 31 '16 at 15:32
  • 4
    It's important that your side-effect function returns a Falsey value here! That's obvious if you've seen this construct before, but less so otherwise :) – Adam Smith Mar 31 '16 at 15:37
  • This is purely for debugging a pile of list comprehensions. I promise to use sparingly. ;) – Chris Mar 31 '16 at 15:37
  • @Chris - another option added to answer. – Robᵩ Mar 31 '16 at 16:10
1

Here's one option that doesn't require anything about what your function returns:

[(myfunc(), i)[1] for i in range(10)]

You can also do more than one function at a time:

[(myfunc(), myfunc2(), i)[-1] for i in range(10)]
zondo
  • 19,901
  • 8
  • 44
  • 83