[Python-ideas] Unpacking iterables for augmented assignment
Steven D'Aprano
steve at pearwood.info
Sun Aug 26 21:40:31 EDT 2018
On Sun, Aug 26, 2018 at 07:50:49PM +0100, Jonathan Fine wrote:
> Hi James and Steve
>
> Myself and Steve wrote:
>
> >> Notice that '+=' creates uses the same object when the object is a
> >> list, but creates a new object. This raises the question: Why and how
> >> does Python behave in this way?
>
> > Lists are mutable and can be modified in place. Tuples are immutable and
> > cannot be.
>
> This correctly answers why this happens.
>
> Steve: I wanted James to think about this question. He learns more
> that way. (I already knew the answer.)
How do you know James doesn't already know the answer too?
If you meant this as a lesson for James, you should have said so. You
shouldn't have claimed to have been surprised by it:
"Finally, here's something that surprised me a little bit"
> James: Combining tuple assignment with increment assignment in a
> single statement will increase the cognitive burden on both writer and
> reader of the line of code.
Each additional line we read has to be read as a separate
operation. Moving things into a single operation can reduce the
cognitive load, at least sometimes.
Reducing the number of lines
x += 1
y += 2
z += 3
down to one:
x, y, z += 1, 2, 3 # Hypothetical syntax
could also *decrease* the cognitive burden on the writer or reader if x,
y, z form a logically connected group. Each additional line of
code has its own cognitive load just by being an extra line to
process.
For a small number of simple targets, our brains can chunk the
assignments into one conceptual operation:
"assign x, y, z"
instead of three:
"assign x; then assign y; also assign z"
Hence a reduced cognitive load on both reader and writer.
I see no reason why this chunking can't also apply to augmented
assignments:
"increment x, y, z"
but I do worry if it would only chunk effectively if the increment is
the same:
x, y, z += 1 # increment each of x, y, z by 1
but not if we have to specify each increment separately:
x, y, z += 1, 1, 1
I don't have any proof of this concern.
[...]
> But I think there's a code-smell here. Better, I think, is to
> introduce a type that supports augmented assignment. For example
>
> > vec = Vector(a, b)
> > inc = Vector(c, d)
> > vec += inc
I would like to see Python increase its support for vectorized
operations. Some years ago I tried adding vectorized support to the
statistics module as an experiment, but I found that the performance hit
was horrible, so I abandoned the experiment.
YMMV.
Julia includes syntax to automatically vectorize any operator or
function:
https://docs.julialang.org/en/v0.6.2/manual/functions/#man-vectorized-1
but that's moving away from the topic on hand.
(Any responses to my vectorization comment, please start a new thread or
at least change the subject line.)
Back to the original topic...
My gut feeling is that this suggested syntax would work well if there
was a single value on the right hand side, so that:
spam, eggs, cheese += foo
is approximately equivalent to:
# evaluate RHS only once
_tmp = foo
spam += _tmp
eggs += _tmp
cheese += _tmp
but not so well if we add sequence unpacking on the RHS:
spam, eggs, cheese += foo, bar, baz
Without adding new syntax, I think we can only pick one set of
semantics, not both: either a single RHS value, or multiple values.
My intuition is that the first version (a single value on the RHS) is
not only more useful, but also more readable, since it allows the reader
to chunk the operation to "increment these three targets" while the
second doesn't.
That also leaves the door open in the future to adding a vectorized
version of augmented assignment, if and when we add syntax for
vectorizing operations a la Julia.
So... a tentative +1 to allowing:
spam, eggs += foo
and an even more tentative -0 to:
spam, eggs += foo, bar
--
Steve
More information about the Python-ideas
mailing list