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?
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]
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)
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?
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]
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)