3

I'm trying to make a callback that updates if it's been more than a second since the last report. It looks something like this

def main_func()
    ...
    start_time = time.time()
    def callback():
        current_time = time.time()
        if current_time - start_time > 1.0:
            print 'working'
            start_time = time.time()
    work_function(args, callback)

Since start_time is local the global keyword won't work inside callback. Is there a Python paradigm that can handle adding state to local functions?

Rich
  • 12,068
  • 9
  • 62
  • 94

3 Answers3

3

As already suggested, you're probably better off using a class, and saving the state as a member.

Also as already suggested, you can use a global variable, or the nonlocal statement.

A third (and more original) alternative would be to set the state as an attribute of the function object:

def main_func()
    ...
    def callback():
        current_time = time.time()
        if current_time - callback.start_time > 1.0:
            print 'working'
            callback.start_time = time.time()
    callback.start_time = time.time()
    work_function(args, callback)
shx2
  • 61,779
  • 13
  • 130
  • 153
0

You can make this work, though the details will depend on which version of Python you're using.

In Python 3, you can use a nonlocal statement to allow your callback function to assign a new value to the start_time variable in the outer function's scope.

def main_func()
    ...
    start_time = time.time()
    def callback():
        nonlocal start_time            # new line here
        current_time = time.time()
        if current_time - start_time > 1.0:
            print 'working'
            start_time = time.time()   # this assignment now works as intended
    work_function(args, callback)

In Python 2, nonlocal is not available, but you can wrap the value up in a mutable container (like a list) and modify the value without reassigning the variable:

def main_func()
    ...
    start_time = [time.time()]             # wrap time value in a list
    def callback():
        current_time = time.time()
        if current_time - start_time > 1.0:
            print 'working'
            start_time[0] = time.time()    # modify the list in place
    work_function(args, callback)
Blckknght
  • 100,903
  • 11
  • 120
  • 169
0

Kinda, but it's durdly.

    def foo(a):
        def inner(b):
            if b > c[0]:
                c[0] > b
            else:
                print "too low"
        c = [a]
        return inner

>>> bar = foo(5)
>>> bar(5)
too low
>>> bar(6) # silence on success
>>> bar(5)
too low

As others have pointed out, it's probably best to just use an object (which you kind of do with this solution -- lists are objects after all)