[Python-ideas] A "local" pseudo-function

Chris Angelico rosuav at gmail.com
Sat Apr 28 13:36:56 EDT 2018


On Sat, Apr 28, 2018 at 12:37 PM, Tim Peters <tim.peters at gmail.com> wrote:
> This is one that little else really handled nicely:
>
> r1, r2 = local(D = b**2 - 4*a*c,
>                sqrtD = math.sqrt(D),
>                twoa = 2*a,
>                ((-b + sqrtD)/twoa, (-b - sqrtD)/twoa))
>
> Everyone's favorite:
>
> if local(m = re.match(regexp, line)):
>     print(m.group(0))
>
> Here's where it's truly essential that the compiler know everything
> about "local", because in _that_ context it's required that the new
> scope extend through the end of the entire block construct (exactly
> what that means TBD - certainly through the end of the `if` block, but
> possibly also through the end of its associated (if any) `elif` and
> `else` blocks - and similarly for while/else constructs).

I'm concerned that there are, in effect, two quite different uses of
the exact same syntax.

1) In an arbitrary expression, local() creates a scope that is defined
entirely by the parentheses.

2) In an 'if' header, the exact same local() call creates a scope that
extends to the corresponding suite.

For instance:

a = 1; b = 2
x = a + local(a = 3, b = 4, a + b) + b
if x == 10:
    # Prints "x is 10: 1 2"
    print("x is 10: ", a, b)

This makes reasonable sense. The parentheses completely enclose the
local scope. It's compiler magic, and you cannot explain it as a
function call, but it makes intuitive sense. But the same thing inside
the if header itself would be much weirder. I'm actually not even sure
what it would do. And you've clearly shown that the local() call can
be anywhere inside the condition, based on these examples:

> Of course that example could also be written as:
>
> if local(m = re.match(regexp, line), m):
>     print(m.group(0))
>
> or more specifically:
>
> if local(m = re.match(regexp, line), m is not None):
>     print(m.group(0))
>
> or even:
>
> if local(m = re.match(regexp, line)) is not None:
>     print(m.group(0))

At what point does the name 'm' stop referring to the local? More generally:

if local(m = ...) is not m:
    print("Will I ever happen?")

Perhaps it would be better to make this special case *extremely*
special. For instance:

if_local: 'if' 'local' '(' local_item (',' local_item)* ')' ':' suite

as the ONLY way to have the local names persist. In other words, if
you tack "is not None" onto the outside of the local() call, it
becomes a regular expression-local, and its names die at the close
parentheses. It'd still be a special case, but it'd be a bit saner to
try to think about.

ChrisA


More information about the Python-ideas mailing list