Python3.8 assignment expressions, use in list comprehension or as an expression

Question:

I recently discovered that assignment expressions exist. And I wanted to refactor some of my code to make use of them. Most of the places I wanted to use it were relatively straightforward to convert.

However, I’m not sure of the syntax to use for this particular function. Is there a way I could replace my usage of functools.reduce with assignment expressions?

from functools import reduce

def get_average(xs):
    """
    This function takes in a list of nx3 lists and returns the average
    along each column, returning a 3 length list.
    """
    return [
        x / len(xs)
        for x in reduce(
            lambda acc, x: [sum(z) for z in zip(acc, x)],
            xs,
            [0, 0, 0])]

It’s not straightforward to me how to use the result of an assignment expression as an expression directly. Is there a nice and pythonic way to do this?

Asked By: OmnipotentEntity

||

Answers:

You don’t need assignment expressions here, see this simple list comprehension:

[sum(i)/len(i) for i in zip(*l)]

example:

# input
l = [[1,2,3], [4,5,6]]

# output
[2.5, 3.5, 4.5]
Answered By: mozway

I just discovered it too, and I must admit it opens new gates to comprehensions and generator expressions (Love it 😉 )

Here is an example of a discrete integral:

s = 0
ditg = [(s := s+i) for i in range(10)]

here is finite differences:

s = 0
fdif = [(-s+(s:=x)) for x in range(10)]

and a fibonacci suite:

i0 = -1; i1 = 1 # with a i[-2] & i[-1] preset
fibo = [i1 := i0 + (i0 := i1) for j in range(0,10)]

or (if you want the normal preset)

fibo = [i0 := 0, i1 := 1]+[i1 := i0 + (i0 := i1) for j in range(2,10)]

Those can also be written as generator expressions:

s = 0
ditg = ((s := s+i) for i in range(10))

,

s = 0
fdif = ((-s+(s:=x)) for x in range(10))

and

i0 = -1; i1 = 1 # with a i[-2] & i[-1] preset
fibo = (i1 := i0 + (i0 := i1) for j in range(0,10))

but the Fibonacci suite with the "normal" preset is a bit trickier, because you cannot just add generator expression as you would with lists and because of a feature/bug (not sure), the "obvious" answer: fibo = (v for g in ((i0 := 0, i1 := 1), (i1 := i0 + (i0 := i1) for j in range(2,10))) for v in g) doesn’t work. However, it is OK if you get the subgenerators list outside (that’s the reason why I suspect a bug) :

glist = ((i0 := 0, i1 := 1), (i1 := i0 + (i0 := i1) for j in range(2, 5)))
fibo = (v for g in glist for v in g)
Answered By: Camion