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

Nathaniel Smith njs at pobox.com
Sat May 5 00:25:26 EDT 2018

On Fri, May 4, 2018 at 6:56 PM, Alexander Belopolsky
<alexander.belopolsky at gmail.com> wrote:
> On Fri, May 4, 2018 at 8:06 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>> ...
>> With that spelling, the three examples above would become:
>>     # Exactly one branch is executed here
>>     if m given m = pattern.search(data):
>>         ...
>>     elif m given m = other_pattern.search(data)):
>>         ...
>>     else:
>>         ...
>>     # This name is rebound on each trip around the loop
>>     while m given m = pattern.search(remaining_data):
>>         ...
>>     # "f(x)" is only evaluated once on each iteration
>>     result = [(x, y, x/y) for x in data if y given y = f(x)]
> I think this is a step in the right direction.  I stayed away from the
> PEP 572 discussions because while intuitively it felt wrong, I could
> not formulate what exactly was wrong with the assignment expressions
> proposals.  This proposal has finally made me realize why I did not
> like PEP 572.  The strong expression vs. statement dichotomy is one of
> the key features that set Python apart from many other languages and
> it makes Python programs much easier to understand.  Right from the
> title, "Assignment Expressions", PEP 572 was set to destroy the very
> feature that in my view is responsible for much of Python's success.

This is what makes me uncomfortable too. As Dijkstra once wrote:

"our intellectual powers are rather geared to master static relations
and ... our powers to visualize processes evolving in time are
relatively poorly developed. For that reason we should do (as wise
programmers aware of our limitations) our utmost to shorten the
conceptual gap between the static program and the dynamic process, to
make the correspondence between the program (spread out in text space)
and the process (spread out in time) as trivial as possible." [1]

Normally, Python code strongly maps *time* onto *vertical position*:
one side-effect per line. Of course there is some specific
order-of-operations for everything inside an individual line that the
interpreter has to keep track of, but I basically never have to care
about that myself. But by definition, := involves embedding
side-effects within expressions, so suddenly I do have to care after
all. Except... for the three cases Nick wrote above, where the
side-effect occurs at the very end of the evaluation. And these also
seem to be the three cases that have the most compelling use cases
anyway. So restricting to just those three cases makes it much more
palatable to me.

(I won't comment on Nick's actual proposal, which is a bit more
complicated than those examples, since it allows things like 'if
m.group(1) given m = ...'.)

(And on another note, I also wonder if all this pent-up desire to
enrich the syntax of comprehensions means that we should add some kind
of multi-line version of comprehensions, that doesn't require the
awkwardness of explicitly accumulating a list or creating a nested
function to yield out of. Not sure what that would look like, but
people sure seem to want it.)


[1] This is from "Go to statement considered harmful". Then a few
lines later he uses a sequence of assignment statements as an example,
and says that the wonderful thing about this example is that there's a
1-1 correspondence between lines and distinguishable program states,
which is also uncannily apropos.

Nathaniel J. Smith -- https://vorpus.org

More information about the Python-ideas mailing list