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/