I wrote some code wrong and found my bug, which is that I reassigned a mutable variable locally. However, the observed behavior confused me.
Here is a minimal example:
import numpy as np
n = 138
MQ = np.zeros((n, 0))
def calc(v):
print(v)
#do some complicated math
if v % 16 == 3:
q = np.random.random((n, 1))
MQ = np.hstack((MQ, q))
else:
#do some complicated math and eventually call function recursively
pass
calc(v-1)
calc(700)
As you can see, MQ is bound to a numpy array initially of size (138, 0) and the recursive function stacks some (138,1) arrays onto it when some complicated math things happen, the intention being to find some valid 138 dimensional vectors that solve the complicated math problem.
Of course, the bug here is that MQ
is reassigned each recursion and will never mutate correctly because nothing in the code actually mutates it.
However, the behavior that I would expect from this example is, that on every recursion, the calc()
function does not have the new incarnation of the variable MQ
, instead it has the version of MQ that it closed over, which is an 138x0 array that was reassigned in the previous recursive call, but the original was never touched.
Instead, the behavior observed when running this example is UnboundLocalError: local variable 'MQ' referenced before assignment
. Why is this? Clearly the recursive function closes over MQ
, how can it be unbound?