title: Tracking number of function calls + closures (à la SICP) in Python
body: <p>This is a question about <strong>scope</strong> and <strong>closures</strong> in <strong>Python</strong>, motivated by an exercise in SICP. Much thanks for your time if you read this!</p>
  
  <p>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).</p>
  
  <p>Here is code in Scheme that I wrote that works:</p>
  
  <pre><code>(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))
  </code></pre>
  
  <p>My question however is about <strong>how to write this in a "pythonic" way</strong>. 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?</p>
  
  <p>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) </p>
  
  <pre><code>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
  </code></pre>
  
  <p>PS: This question is related to <a href="https://stackoverflow.com/questions/27591403/sicp-section-3-1-1-local-state-in-procedures-seems-inconsistent">this same set of exercises in SICP</a> but my question is really about Python best practice and not the concept of closures or Scheme...</p>