[Python-ideas] "given" vs ":=" in list comprehensions

Chris Angelico rosuav at gmail.com
Sat May 12 20:55:12 EDT 2018


On Sun, May 13, 2018 at 10:34 AM, Andre Roberge <andre.roberge at gmail.com> wrote:
> Second example: multiple assignments.
>
> When we have multiple temporary assignments, the situation can be more
> complicated.  In the following series of examples, I will start in reverse
> order compared to above.
>
> 5) using *where* before the iterations
>
> real_roots2 = [ (-b/(2*a) + D, -b/(2*a) - D)
>                              where D= sqrt( (b/(2*a))**2 - c/a)
>                              where c = c_values/100
>                          for c_values in range(1000)
>                          if D >= 0]
>
> 6) using *given* before the iterations
>
> real_roots2 = [ (-b/(2*a) + D, -b/(2*a) - D)
>                              given D= sqrt( (b/(2*a))**2 - c/a)
>                              given c = c_values/100
>                          for c_values in range(1000)
>                          if D >= 0]
>
> 7) using *given* at the very end
>
> real_roots2 = [ (-b/(2*a) + D, -b/(2*a) - D)
>                          for c_values in range(1000)
>                          if D >= 0
>                          given D= sqrt( (b/(2*a))**2 - c/a)
>                          given c = c_values/100]

In what order are multiple assignments performed? I guarantee you that
whichever you pick, people will wonder why you didn't pick the other.
For instance, you've used the word "given" twice, and they appear to
nest; but can you use 'c' in the main body?

The 'for' loops all execute left to right. Now you're introducing
'given' statements that execute from right to left. I think.

> 8) Using :=
>
> real_roots2 = [  ( -b/(2*a) + (D:= sqrt( (b/(2*a))**2 -
> (c:=c_values/100)/a),
>                            -b/(2*a) - D)
>                          for c_values in range(1000)
>                          if D >= 0]
>
> I find this last version extremely difficult to understand compared with the
> others where a keyword is used.  Perhaps it is because I do not fully
> understand how := should be used...

It's used where you want to have an expression that you then capture
the value of.

> Finally ... if "where" cannot be used, given the very special status of such
> temporary assignments, could "where_" (with a trailing underscore) be
> considered? I would argue that any word followed by an underscore would be
> more readable than a compound symbol such as ":=".

Definitely not. There is a strong convention around Python that goes
the opposite way: if you want to use a keyword like "class" in your
API, you use "class_" to avoid the clash. Creating a keyword that
inverts this is going to cause nothing but pain.

For the situation you're looking for, 'given' is going to be at least
as good. But I am still far from convinced that it's better than ':='.
Pushing the expression out-of-line creates confusing order of
evaluation, whereas prepending 'NAME :=' to an expression doesn't
change when anything's evaluated.

ChrisA


More information about the Python-ideas mailing list