[Python-ideas] PEP 572 version 2: Statement-Local Name Bindings

Brendan Barnwell brenbarn at brenbarn.net
Fri Mar 2 13:30:38 EST 2018


On 2018-03-02 03:43, Chris Angelico wrote:
> After dozens of posts and a wide variety of useful opinions and
> concerns being raised, here is the newest version of PEP 572 for your
> debating pleasure.

	After following the discussion here, I think I've come to the 
conclusion that something like "EXPR with NAME as VALUE" is better, and 
that's because the "out-of-order" execution there is actually a benefit.

	The example that gave me the most pause in this thread was Paul Moore's 
involving the quadratic formula (slightly emended here :-):

x = [(-b + sqrt((b**2 - 4*a*c as D))/(2*a), (-b + sqrt(D)/(2*a)]

	To me this is a classic example of the kind of thing I would want to do 
with a statement-local binding, so whatever syntax is chosen won't be 
useful to me if it doesn't nicely work in situations like this.

	But I don't find the above example nice, for more or less the reason 
Paul cited: the need to assign the expression "inline" (at the point 
where it's first defined) creates an asymmetry that masks the fact that 
it's the same expression being re-used elsewhere --- and it's exactly 
that re-use that I would want to HIGHLIGHT with a statement-local binding.

	The alternative with the name binding at the end is much better:

x = [(-b + sqrt(D))/(2*a), (-b - sqrt(D))/(2*a) with b**2 - 4*a*c as D]

	To my mind, it's a real desideratum for a statement-local binding that 
it should pull the bound expression OUT of the enclosing context.  The 
overall statement gains in readability only if the reader can easily see 
a shared element across multiple parts.  If I can't tell at a glance 
that the two roots both involve the same value D, there's little point 
in having a statement-local binding for it.  (It still may gain in 
computational cost, since the expression won't have to be evaluated 
multiple times, but I see that as a much less important benefit than 
readability.)

	Also note that the version above comes perilously close to the existing 
solution with a regular local variable:

D = b**2 - 4*a*c
x = [(-b + sqrt(D))/(2*a), (-b - sqrt(D))/(2*a)]

	The only difference is that now D is "leaked" to following code.  Nick 
Coghlan has argued that there's no point in an inline-assignment 
construct if it's not somehow local, since a big part of its purpose is 
to simplify reasoning by avoiding any stomping on "real" local variables.

	But if that's the case, maybe what we want is actually another thing 
that's been discussed many times on this list, namely something like a 
with-block that can define "super-local" variables that disappear at the 
end of the block:

with b**2 - 4*a*c as D:
     x = [(-b + sqrt(D))/(2*a), (-b - sqrt(D))/(2*a)]

	This the same as my earlier version with "with", except the with clause 
comes at the beginning.

	There's no need to go into extreme detail here on these proposals as 
they're not really what's proposed by this PEP.  But my point is that, 
from my perspective, they have something crucial that the current 
proposal lacks: they explicitly separate the *definition* of the shared 
expression from its *use* within the statement.  Having to do the 
name-binding inline at the place where the re-used expression happens to 
occur makes the overall construct LESS readable for me, not more, so I'm 
-1 on the current proposal.

-- 
Brendan Barnwell
"Do not follow where the path may lead.  Go, instead, where there is no 
path, and leave a trail."
    --author unknown


More information about the Python-ideas mailing list