On Fri, May 28, 2021 at 10:11 PM Steven D'Aprano <st...@pearwood.info> wrote:
>
> On Fri, May 28, 2021 at 04:20:15AM +1000, Chris Angelico wrote:
>
> > def f():
> >     static x = 0
> >     x += 1
> >     yield x
> >
> > next(f())
> > next(f())
> > next(f())
> >
> > will yield 1 every time?
>
> I think that this example has just about convinced me that Chris'
> approach is correct. I wasn't thinking about generators or recursion.
>
> I think that closure nonlocals are almost as fast as locals, so we might
> be able to use the closure mechanism to get this. Something vaguely
> like this:
>
>     def func():
>         static var = initial
>         body
>
> is transformed into:
>
>     def factory():
>         var = initial
>         def func():
>             nonlocal var
>             body
>         return func
>     func = factory()
>
>
> except that the factory is never actually exposed to Python code.

I think that would probably work, but even better would be if the
outer function didn't actually exist. A bit of playing around suggests
that LOAD_DEREF could just work here. If you have multiple levels of
nonlocals, the function flattens them out into a tuple in
f.__closure__, identifying them by index. Statics could be another
level of nonlocals that doesn't actually require a function as such.

In terms of describing the semantics, I think this is probably the
cleanest way to give a pure-Python equivalent.

> It would be nice if there was some way to introspect the value of `var`
> but if there is a way to do it I don't know it.

No idea about other implementations, but in CPython, you can look at
f.__closure__[*].cell_contents, but you'd need to know the mapping
from static name to lookup index. I think the corresponding names are
in f.__code__.co_freevars, but I'm not sure if there are any other
things that go in there.

> We might not even need new syntax if we could do that transformation
> using a decorator.
>
>
>     @static(var=initial)
>     def func():
>         body
>

Hmm, there'd need to be some transformations, since the code generator
is always going to use lexical scope. You can't magically change a
LOAD_GLOBAL into a LOAD_DEREF with a decorator - the only way would be
to do some fairly hairy rewriting, and you might lose a lot of the
efficiency. This really needs proper compiler support, and if it gets
compiler support, it may as well have dedicated syntax.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/7CXYEBUKVCLB3O6APOG5TUMPACWFVUGY/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to