3

I am looking for a way to do assignments in a list comprehension. I would like to rewrite something like the following piece of code into a list comprehension.

I have this "costly" function:

import time
def f(x):
    time.sleep(1)
    return x + 1

And this loop:

l = []
for value in [1, 2, 3]:
    x = f(value)
    l.append(x + x)

I would like to rewrite this to a list comprehension:

l = [
     f(value) + f(fvalue)
     for value in [1, 2, 3]
]

But since calling f(value) is costly, I would like to minimize the number of calls (this following snippet doesn't run):

l = [
     (x = f(value))
     x + x
     for value in [1, 2, 3]
]

I've read about the assignment expression (:=) (https://www.python.org/dev/peps/pep-0572/#changing-the-scope-rules-for-comprehensions) but I can't seem to figure it out.

4
  • For the given example, does l = [x*10 for x in [1, 2, 3]] work? Commented Jan 16, 2022 at 13:12
  • Does this answer your question? How can I do assignments in a list comprehension? Commented Jan 16, 2022 at 13:14
  • Does not work! x, y = f(value) requires f to return an iterable of 2 values, while your example only return a scalar. Commented Jan 16, 2022 at 13:48
  • After a second look,I think that you wanted ... return x, x+1 Commented Jan 16, 2022 at 13:54

3 Answers 3

2

My approach would be to nest multiple list comprehension, like

l_new = [x * x * y for x, y in [f(value) for value in [1, 2, 3]]]

So f() should only be called once for each value.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your answer. The problem for me would be that we introduce an extra loop which makes it a bit unreadable to me
0

Here is another way to fake it:

[x+x for value in [1, 2, 3] for x in [f(value)]]

Comments

-1

This can be done with a walrus operator. Note that you need Python 3.8 or later.

l = [x:=10 * value for value in [1, 2, 3]]

With one fast and slow function.

import time

def slow_function(a):
    time.sleep(1)
    return a + 1

def fast_function(b):
    return b + b  


l = [
     fast_function(x := slow_function(value))
     for value in [1, 2, 3]
]

The walrus operator can be skipped in both these examples, but perhaps the real problem would require it.

8 Comments

I think you don’t even need walrus assignment here, right?
Yeah for the original example I made this is true. I updated the post to demonstrate my problem more clearly.
In that case you could write one fast and one slow function, like this.
What would be the use of the walrus operator? Since x is not (re-)used
You could write it as e.g. l = [(x := f(value), x + x)[1] for value in [1, 2, 3]], if you're willing to create a tuple and take the second element of it inside the list comprehension.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.