pythonpython-3.xvariablesscope

How to preserve state in a function?


When using a class, I can preserve a state using a property:

class Hello:

    def __init__(self):
        self.hello = 1

    def add_one(self):
        if self.hello < 3:
            self.hello += 1
        else:
            self.hello = 1

h = Hello()
for _ in range(5):
    h.add_one()
    print(h.hello)

# output
2
3
1
2
3

In between calls to h.add_one(), the state is preserved in h.hello.

Is there an equivalent mechanism in functions? Something along the lines of

def add_one():
    a_special_kind_of_variable_which_is_not_reinitialized hello
    if hello_is_not_initialized:
        hello = 1
    if hello < 3:
        hello += 1
    else:
        hello = 1
    return hello

for _ in range(5):
    print(add_one())

# same output as above

Solution

  • Python does not have C-style static variables. However, you can simulate them with closures.

    def make_add_one():
        x = 0
        def _():
            nonlocal x
            if x < 3:
               x += 1
            else:
                x = 1
            return x
        return _
    
    add_one = make_add_one()
    
    for _ in range(5):
        print(add_one())
    

    There is a duality between objects (data with functions) and closures (functions with data); compare to the class defined by Carcigenicate (slightly modified):

    class AddOne:
        def __init__(self):
            self.hello = 0
    
        def __call__(self):
            if self.hello < 3:
                self.hello += 1
            else:
                self.hello = 1
            return self.hello
    
    add_one = AddOne()
    for _ in range(5):
        print(add_one())
    

    One can see the following correspondences: