This is a question about scope and closures in Python, motivated by an exercise in SICP. Much thanks for your time if you read this!
A question (3.2) in SICP asks one to create a procedure "make-monitored", that takes in a function f (of one parameter) as input and returns a procedure that keeps track of how many times f has been called. (If the input to this new procedure is "num-calls" it returns the number of times f has been called, if it is "reset" it resets counter to 0 and anything else, it applies f to the input and returns the result (after appropriately incrementing the counter).
Here is code in Scheme that I wrote that works:
(define (make-monitored f)
(let ((counter 0))
(define (number-calls) counter)
(define (reset-count)
(set! counter 0))
(define (call-f input)
(begin (set! counter (+ 1 counter))
(f input)))
(define (dispatch message)
(cond ((eq? message 'num-calls) (number-calls))
((eq? message 'reset) (reset-count))
(else (call-f message))))
dispatch))
My question however is about how to write this in a "pythonic" way. My attempt below is obviously a direct translation of my Scheme code and I realize that though it is fine for an impure functional language (like Scheme) it's probably not the cleanest or best way to do it in Python. How does one solve a general problem like this in Python where you want a higher order procedure to dispatch on type and remember local state?
Below is my noobish attempt that works (earlier I had said it did not but the problem was that an earlier version of the program was still in the terminal's memory) (In 2 it seems hard to make nonlocal variable binding)
def make_monitored(func):
counter = 0
def dispatch(message):
if message == "num-calls":
return num_calls()
elif message == "reset":
reset()
else:
nonlocal counter
counter += 1
return func(message)
def num_calls():
nonlocal counter
return counter
def reset():
nonlocal counter
counter = 0
return dispatch
PS: This question is related to this same set of exercises in SICP but my question is really about Python best practice and not the concept of closures or Scheme...