I was thinking about introducing new opcodes for implementing static variables. Not sure though. All of the ideas actually do the same thing. The difference is approach.
On Fri, May 28, 2021 at 6:57 PM Chris Angelico firstname.lastname@example.org wrote:
On Fri, May 28, 2021 at 10:11 PM Steven D'Aprano email@example.com 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 -- firstname.lastname@example.org To unsubscribe send an email to email@example.com https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://firstname.lastname@example.org/message/7CXYEB... Code of Conduct: http://python.org/psf/codeofconduct/