Walrus operator example in PEP572
Asked Answered
D

2

2

One of the examples given in PEP572 is

# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]

currently in python, you'd have to do one of the following:

# option 1
y = f(x)
[y, y**2, y**3]

or

# option 2 
[f(x), f(x)**2, f(x)**3]

the example implies that option 2 here could be improved, but I have never seen that recommended over the first option. Is there ever a reason why option 2 (and therefore the walrus operator) would be better than option 1?

Decompensation answered 1/8, 2019 at 12:30 Comment(3)
Could you label more clearly which options you are referring to?Stupe
The walrus operator is basically a flavor of the assignment operator that can be used in contexts where the usage of the latter is not allowed by the grammar, so the first two options should be equivalent.Bemoan
Anyway y = f(x); [y, y**2, y**3] and [f(x), f(x)**2, f(x)**3] are not doing the same thing, in general, and [y := f(x), y**2, y**3] is only equivalent to the two-line code.Stupe
S
7

Just to make things clear:

[y := f(x), y**2, y**3]

is equivalent to:

y = f(x)
[y, y**2, y**3]

(f(x) is called only once)

but, in general, not this:

[f(x), f(x)**2, f(x)**3]

(f(x) is called three times)

because of potential f() side-effects (or potential unnecessary computational burden, if f() is a pure function).

So, in general, replacing [f(x), f(x)**2, f(x)**3] with [y := f(x), y**2, y**3] should be inspected carefully.


For example:

def f(x):
    print('Brooks was here.')
    return 2 * x


x = 1
y = f(x)
l1 = [y, y**2, y**3]

prints Brooks was here. once, while:

l2 = [f(x), f(x)**2, f(x)**3]

will print Brooks was here. three times. Of course, l1 == l2.


So, to answer your question more directly, you may want to use:

[f(x), f(x)**2, f(x)**3]

and not this

y = f(x)
[y, y**2, y**3]

when you are specifically interested in the side-effects, whatever that might be.

Stupe answered 1/8, 2019 at 12:42 Comment(6)
+In cases where subsequent f(x) give the same result and there are no side effects, second option allows us to use list comprehensions instead of loops. However, if f(x) takes long/much memory to calculate, we'd have to use loop with 1st option... or keep the list comprehension with the new walrus operator, so we will calculate f(x) only once.Flabbergast
@Flabbergast I was updating precisely that while you were commentingStupe
This makes sense superficially, but I don't see why the PEP example explicitly says "# Reuse a value that's expensive to compute", if it's replacing an example where f(x) is only being computed once?Decompensation
@Decompensation you have to realize that in this case it is only syntactic sugar (coffee?)Stupe
@Stupe ah, I guess I hadn't thought of the example where the function has side effectsDecompensation
python.org/dev/peps/pep-0572/#rationale [Naming the result of an expression] is available only in statement form, making it unavailable in list comprehensions and other expression contexts. Additionally, naming sub-parts of a large expression can assist an interactive debugger, providing useful display hooks and partial results.Adopted
F
1

A walrus with dynamic programming, it could be faster depend on f(x).

e = 1
[e := e * f(x) for i in range(1, 4)]
Flow answered 16/2, 2020 at 22:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.