Python Forum

Full Version: function state between calls
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
when i write a function that needs to keep state (such as a count of the number of times it has been called) what i have been doing is putting a variable in the global name space and working with that. one problem i have been worrying about is name space conflict. can you suggest the best way to avoid that problem? is there a better way to make a function that can keep state between calls w/o using globals or classes?
classes are pretty powerful. They have many different uses.
@classmethod and @staticmethod could achieve this pretty easily.
class man:
    x = 0

    @classmethod
    def working(cls, value):
        cls.x += value
        print(cls.x)

man.working(8)
man.working(7)
man.working(8)
Generators are keeping the state between calls.
Here are 3 solutions: the first one uses a function object spam, the second one stores an attribute in the function itself eggs, and the third one uses the parameter list to store a static object, using the fact that the parameter list is initialized at function's definition ham
class spam:
    __name__ = 'spam'
    x = 0
    def __call__(self, value):
        self.x += value
        return self.x
spam = spam()

def run(func):
    for v in (8, 7, 8):
        print('{}({}) --> {}'.format(func.__name__,v, func(v)))
    print()

run(spam)

def eggs(value):
    eggs.x += value
    return eggs.x
eggs.x = 0

run(eggs)

class Static:
    def __init__(self, *args, **kwargs):
        self.__dict__.update(*args, **kwargs)
        
def ham(value, static=Static(x=0)):
    static.x += value
    return static.x

run(ham)
The output is
Output:
spam(8) --> 8 spam(7) --> 15 spam(8) --> 23 eggs(8) --> 8 eggs(7) --> 15 eggs(8) --> 23 ham(8) --> 8 ham(7) --> 15 ham(8) --> 23
Here two more options
class Counter:
    counter = {}

    @classmethod
    def grab(cls, key):
        cls.counter[key] = cls.counter.get(key, 0) + 1
        return cls.counter[key]

def myfunc():
    counter = Counter.grab('x')
    print(counter)

myfunc()
myfunc()
myfunc()

class Counter:
    pass

def myfunc():
    try:
        Counter.x += 1
    except:
        Counter.x = 1

    print(Counter.x)

myfunc()
myfunc()
myfunc()

Probably a better option is just to profile your code.
python -m cProfile yourcode.py

It tells you how many times a function been called.

profile of mycode above
Output:
25 function calls in 0.000 seconds Ordered by: call count ncalls tottime percall cumtime percall filename:lineno(function) 6 0.000 0.000 0.000 0.000 {built-in method builtins.print} 3 0.000 0.000 0.000 0.000 help6.py:5(grab) 3 0.000 0.000 0.000 0.000 help6.py:21(myfunc) 3 0.000 0.000 0.000 0.000 help6.py:10(myfunc) 3 0.000 0.000 0.000 0.000 {method 'get' of 'dict' objects} 2 0.000 0.000 0.000 0.000 {built-in method builtins.__build_class__} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 1 0.000 0.000 0.000 0.000 help6.py:18(Counter) 1 0.000 0.000 0.000 0.000 help6.py:2(Counter) 1 0.000 0.000 0.000 0.000 help6.py:2(<module>) 1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
counting the number of times a function is called was an example of saving state. it is not what i am trying the achieve.

what i want to do is save information/data between function calls. i have been using classes. i was wondering if there was also another way that could, perhaps, be simpler. i didn't think about generators, but yeah, as a separate context that persists, they have to be saving state.