You can just use nonlocal variables: 

def stator():
    static_var_1 = 0
    def myfunc(n):
        nonlocal static_var_1
        static_var_1 += n
        return static_var_1
    return myfunc

myfunc = stator()
del stator

Or you can attach any variable to the function itself:

def myfunc(n):
    if not hasattr(myfunc, "static_var_1"):
        myfunc.static_var_1 = 0
    myfunc.static_var_1 += n
    return myfunc.static_var_1

There are several options to get the effect that static variables would have,
not to mention that states of this type are better held as class attributes anyway.

# callable singleton - AKA "function": 
class myfunc(metaclass=lambda *args: type(*args)()):
    def __init__(self):
        self.static_var_1 = 0
    def __call__(self, n):
        self.static_var_1 += n
        return self.static_var_1

Or, as you put it in the first e-mail, the static var could be built into a data structure in
the default arguments of the function. 

(There are also contextvars, threading.local, etc...)

I can't see a separate "static"  declaration being of any use. 
Beginners needing the functionality should just resort to either globals or
plain classes to keep state. As you get the way Python works,
there are plenty of ways to keep the state, without making
the language more complicated.

On Thu, 27 May 2021 at 14:06, Chris Angelico <> wrote:
On Fri, May 28, 2021 at 2:44 AM Shreyan Avigyan
<> wrote:
> My proposal is somewhat the sum of all of your ideas. Well I propose there should a STORE_STATIC_FAST opcode that stores a static variable. Static variable will be declared only once and will be initialized to None (statement syntax will be similar to that of global). It will be initialized in MAKE_FUNCTION. Now it will be set by STORE_STATIC_FAST. Where will the variables be stored? It will have references in locals and __statics__. Therefore LOAD_FAST can find it. So I don't hope there will be performance decrease but performance increase is also not guaranteed. :-)

The duplicated store fixes half the problem, but it still fails on the
recursion example that I posted in reply to Steve. It would be a nice
optimization, but it may or may not be sufficient.

> And if these are thread unsafe then is __defaults__ also thread unsafe?

Thread safety isn't a problem with constants. Python guarantees that
internal details (like CPython's reference counts) aren't going to be
trampled on, and inside your code, nothing is going to change
__defaults__ (unless you're doing something bizarre, in which case it
isn't about __defaults__ any more). Thread safety only becomes an
issue when you have something like this:

counter = 0
def get_next():
    global counter
    counter += 1
    return counter

This disassembles to:

  6           0 LOAD_GLOBAL              0 (counter)
              2 LOAD_CONST               1 (1)
              4 INPLACE_ADD
              6 STORE_GLOBAL             0 (counter)

  7           8 LOAD_GLOBAL              0 (counter)
             10 RETURN_VALUE

A context switch can happen between any two of those instructions.
That means one thread could load the global, then another thread could
load the same value, resulting in both of them writing back the same
incremented value. Or, between opcodes 6 and 8 (between the lines of
Python code), you could store the value, then fetch back a different

None of this is a problem if you're using constants. The only reason
to use statics instead of global constants is performance - the
"len=len" trick is specific to this performance advantage - but you
don't have to worry about thread safety.

Python-ideas mailing list --
To unsubscribe send an email to
Message archived at
Code of Conduct: