On Thu, May 27, 2021 at 10:20 PM Steven D'Aprano <[email protected]> wrote:
> Here is a sketch of how this could work, given a function like this:
>
>     def func(arg):
>         static spam, eggs
>         static cheese = expression
>         ...
>
>
> At function declaration time, the two static statements tell the
> compiler to:
>
> * treat spam, eggs and cheese as local variables (use LOAD_FAST instead
>   of LOAD_GLOBAL for lookups);

I don't think LOAD_FAST would be suitable here - isn't it always going
to look in the stack frame?

> * allocate static storage for them using the same (or similar) mechanism
>   used for function default values;

Default values are attached to the function object (in either the
__defaults__ tuple or the __kwdefaults__ dict).

> * spam and eggs get initialised as None;
>
> * cheese gets initialised to the value of `expression`, evaluated
>   at function declaration time just as default arguments are.
>
>
> When the function is called:
>
> * the interpreter automatically initialises the static variables
>   with the stored values;
>
> * when the function exits (whether by return or by raising an
>   exception) the static storage will be updated with the current
>   values of the variables.

Hmm, I see what you mean. Not sure that this is really necessary
though - and it could cause extremely confusing results with
threading.

> As a sketch of one possible implementation, the body of the function
> represented by ellipsis `...` might be transformed to this:
>
>     # initialise statics
>     spam = LOAD_STATIC(0)
>     eggs = LOAD_STATIC(1)
>     cheese = LOAD_STATIC(2)
>     try:
>         # body of the function
>         ...
>     finally:
>        STORE_STATIC(spam, 0)
>        STORE_STATIC(eggs, 1)
>        STORE_STATIC(cheese, 2)
>
>
> One subtlety: what if the body of the function executes `del spam`? No
> problem: the spam variable will become undefined on the next function
> call, which means that subsequent attempts to get its value will raise
> UnboundLocalError:
>
>
>     try:
>         x = spam + 1
>     except UnboundLocalError:
>         spam = 0
>         x = 1
>
>
> I would use this static feature if it existed. +1
>

Agreed, I'd use it too. But I'd define the semantics slightly differently:

* If there's an expression given, evaluate that when the 'def'
statement is executed, same as default args
* Otherwise it'll be uninitialized, or None, bikeshedding opportunity, have fun
* Usage of this name uses a dedicated LOAD_STATIC or STORE_STATIC bytecode
* The values of the statics are stored in some sort of
high-performance cell collection, indexed numerically

It would be acceptable to store statics in a dict, too, but I suspect
that that would negate some or all of the performance advantages.
Whichever way, though, it should ideally be introspectable via a
dunder attribute on the function.

Semantically, this would be very similar to writing code like this:

def count():
    THIS_FUNCTION.__statics__["n"] += 1
    return THIS_FUNCTION.__statics__["n"]
count.__statics__ = {"n": 1}

except that it'd be more optimized (and wouldn't require magic to get
a function self-reference).

Note that the statics *must* be defined on the function, NOT on the
code object. Just like function defaults, they need to be associated
with individual instances of a function.

>>> f = []
>>> for n in range(10):
...     def spam(n=n):
...             # static n=n # Same semantics
...             print(n)
...     f.append(spam)
...

Each spam() should print out its particular number, even though they
all share the same code object.

This has been proposed a few times, never really got a lot of support though.

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

Reply via email to