[Python-Dev] Whatever happened to 'nonlocal x = y'?

Guido van Rossum guido at python.org
Fri Jan 5 18:02:15 EST 2018


I don't like those examples -- "nonlocal foo = bar" sounds like bar is used
as the *initializer*, but it actually is just an assignment that overwrites
the actual initial value. IMO those shouldn't be combined.

On Fri, Jan 5, 2018 at 2:59 PM, Nathaniel Smith <njs at pobox.com> wrote:

> On Fri, Jan 5, 2018 at 7:47 AM, Guido van Rossum <guido at python.org> wrote:
> > I don't recall (though someone with more time might find the discussion
> in
> > the archives or on the tracker). It was never implemented and I think it
> > shouldn't be. So we might as well update the PEP. It wouldn't be
> > particularly useful, since (by definition) the function that declares the
> > nonlocal variable is not its owner, and hence it's unlikely to make
> sense to
> > initialize it here. The same reasoning applies to global BTW.
>
> The reason I got curious and looked into it is that recently I've been
> finding myself using it a lot for passing values back out of
> concurrent functions (examples below). So it does have use cases, but
> I agree that it's not clear how much value is really added by saving a
> line here. Maybe in a year or two if this style catches on as
> idiomatic then it'd be worth revisiting.
>
> #######
>
> Example: run several functions, return the value of the one that
> finishes first (or non-deterministic if several finish at ~the same
> time):
>
> async def race(*async_fns):
>     async with trio.open_nursery() as nursery:
>         winning_value = None
>
>         async def driver(async_fn):
>             nonlocal winning_value
>             winning_value = await async_fn()
>             # we're done, so cancel competitors
>             nursery.cancel_scope.cancel()
>
>         for async_fn in async_fns:
>             nursery.start_soon(driver, async_fn)
>
>     return winner
>
> #######
>
> Example: an async iterator version of zip, with concurrent evaluation
> of the different iterators (based on an idea from github user @matham:
> https://github.com/python-trio/trio/issues/393):
>
> async def async_zip(*aiterables):
>     aiterators = [aiterable.__aiter__() for aiterable in aiterables]
>     done = False
>     while True:
>         items = [None] * len(aiterators)
>
>         async def fill_in(i):
>             try:
>                 items[i] = await aiterators[i].__anext__()
>             except StopAsyncIteration:
>                 nonlocal done
>                 done = True
>
>         async with trio.open_nursery() as nursery:
>             for i in range(len(aiterators)):
>                 nursery.start_soon(fill_in, i)
>
>         if done:
>             break
>
>         yield tuple(items)
>
> -n
>
> --
> Nathaniel J. Smith -- https://vorpus.org
>



-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180105/2ea9faeb/attachment.html>


More information about the Python-Dev mailing list