[Python-Dev] Whatever happened to 'nonlocal x = y'?
Nathaniel Smith
njs at pobox.com
Fri Jan 5 17:59:00 EST 2018
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
More information about the Python-Dev
mailing list