-1

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?

Alex Waygood
  • 6,304
  • 3
  • 24
  • 46
OmnipotentEntity
  • 16,531
  • 6
  • 62
  • 96
  • Can you please clarify what you are asking? There isn't a single assignment expression in the code, and it's not clear where you would want to use one, nor what is meant by "use the result of an assignment expression as an expression directly". – MisterMiyagi Oct 01 '21 at 08:04
  • @MisterMiyagi there isn't an assignment expression in the code because I cannot figure out the syntax on how to use it to replace the `reduce` function. I can't declare a variable in the middle of a list comprehension of which I'm aware, and the expression result of an assignment expression is the scanleft operation, rather than the accumulator. – OmnipotentEntity Oct 01 '21 at 08:06
  • So you are asking how to replace ``reduce`` via assignment expressions? The *syntax* for assignment expressions is always just ``target := expression``. – MisterMiyagi Oct 01 '21 at 08:08
  • I'm asking how to replace this `reduce` (in the middle of a list comprehension) via assignment expressions. I know how to do so normally. – OmnipotentEntity Oct 01 '21 at 08:09
  • 1
    I don't think this is a good place to use an assignment expression. Your function is already too complicated for such a simple task. If you read PEP 572, it will give plenty of examples of where assignment operators are actually useful and improve readability. – Jussi Nurminen Oct 01 '21 at 08:17
  • You might want to clean up the question, then. It seems the actual question is "How to replace ``list(reduce(…))`` with list comprehension + assignment expression?" and the unwieldy code that doesn't seem to need reduce at all is just needlessly complicating things. – MisterMiyagi Oct 01 '21 at 08:19

2 Answers2

2

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]
mozway
  • 194,879
  • 13
  • 39
  • 75
  • Thanks, that certainly solves my "I make awful code at 4AM" problem. But I am still curious as to whether or not it is possible to use an assignment expression in this way. If you like I can come up with a better example. – OmnipotentEntity Oct 01 '21 at 08:00
  • 1
    @OmnipotentEntity yes, please do, I'd be happy to have a look ;) (maybe get some rest before, sleep is important :p) – mozway Oct 01 '21 at 08:04
  • Or not, it seem like it will not let me. Ah well, in that case I'll edit this question in the morning if it's still bothering me. – OmnipotentEntity Oct 01 '21 at 08:22
1

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)
Camion
  • 1,264
  • 9
  • 22