[Python-ideas] Inline assignments using "given" clauses

Steven D'Aprano steve at pearwood.info
Sat May 12 13:24:27 EDT 2018

On Sat, May 12, 2018 at 08:16:07AM -0700, Neil Girdhar wrote:

> I love given compared with := mainly because
> Simpler is better than complex:
> * given breaks a complex statement into two simpler ones,

(Foreshadowing: this argument applies to augmented assignment. See 

I don't see how you justify that statement about "given". I think that 
it is "given" which is more complex. Significantly so.

Let's compare the syntax:

    target := expr

That is a single, simple expression with a single side-effect: it 
assigns the value to <target>. That's it.

Like all expressions, it returns a value, namely the result of "expr". 
Like all expressions, you can embed it in other expressions (possibly 
wrapping it in parens to avoid precedence issues), or not, as required.

(That surrounding expression can be as simple or complex as you like.)

Now here's Nick's syntax:

    target given target = expr

Exactly like the := version above, we can say that this is a single 
expression with a single side-effect. Like all expressions, it returns a 
value, namely the result of "expr", and like all expressions, you can 
embed it in other expressions.

So far the two are precisely the same. There is no difference in the
complexity, because they are exactly the same except for the redundant 
and verbose "given" spelling.

But actually, I lied.

Nick's syntax is *much more complicated* than the := syntax. Any 
arbitrary expression can appear on the left of "given". It need not 
even involve the binding target! So to make a fair comparison, I ought 
to compare:

    target := expr

which evaluates a single expression, binds it, and returns it, to:

    another_expr given target := expr

which evaluates "expr", binds it to "target", evaluates a SECOND
unrelated expression, and returns that.

If you want to argue that this is more useful, then fine, say so. But to 
say that it is *simpler* makes no sense to me.

Option 1: evaluate and bind a single expression

Option 2: exactly the same as Option 1, and then evaluate a second

How do you justify that Option 2 "given", which does everything := does 
PLUS MORE, is simpler than Option 1?

That's not a rhetorical question.

> which is putting people off in the simple examples shown here (some 
> people are annoyed by the extra characters).  However, when given is 
> used in a list comprehension to prevent having to re-express it as a 
> for loop, then two simple statements are easier to understand than one 
> complex statement.

I'd like to see an example of one of these list comprehensions that is 
simpler written with given. Here's an earlier example, an exponentially 
weighted running average:

average = 0
smooth_signal = [(average := (1-decay)*average + decay*x) for x in signal]
assert average == smooth_signal[-1]

I'm not even sure if "given" will support this. Nick is arguing strongly 
that bound targets should be local to the comprehension, and so I think 
you can't even write this example at all with Nick's scoping rule.

But let's assume that the scoping rule is the same as the above. In that 
case, I make it:

average = 0
smooth_signal = [average given average = (1-decay)*average + decay*x) for x in signal]

Is it longer, requiring more typing? Absolutely.

Does it contain a redundantly repetitious duplication of the repeated 
target name? Certainly.

But is it simpler? I don't think so.

If you don't like the exponential running average, here's a simple 
running total:

total = 0
running_totals = [total := total + x for x in xs]


total = 0
running_totals = [total given total = total + x for x in xs]

If you don't like this example either, please show me an example of an 
actual list comp that given makes simpler.

> This is a 
> common difference between code written at programming contests versus code 
> written by those same software engineers years later at big companies.  
> Code that you write for yourself can be compact because you already 
> understand it, but code you write professionally is read many many more 
> times than it is written.  Accessibility is much more important than 
> concision. 

Ah, nice rhetorical argument: "given" is for professionals, := is a hack 
for amateurs and programming contests. Seriously?

Do you use augmented assignment? Your simple versus complex argument for 
"given" applies well to augmented assignment.

Augmented assignment combines two conceptual operations:

    x = x + 1
    - addition (for example)
    - assignment

into a single operator:

    x += 1

By your argument, augmented assignment is more complex, and we ought to 
prefer splitting it into two separate operations x = x + 1 because 
that's simpler.

I think I agree that x = x + 1 *is* simpler. We can understand it by 
understanding the two parts separately: x+1, followed by assignment.

Whereas += requires us to understand that the syntax not only calls a 
dunder method __iadd__ (or __add__ if that doesn't exist), which 
potentially can operate in place, but it also does an assignment, all in 
one conceptual operation. There's a whole lot of extra complexity there.

That doesn't mean I agree with your conclusion that we ought to prefer 
the simpler version, let alone that the complex case (augmented 
assignment) is fit only for programming contests and that professionals 
ought to choose the simpler one.


More information about the Python-ideas mailing list