In Python 2, how do I write to variable in the parent scope?

I have the following code inside a function:

stored_blocks = {}
def replace_blocks(m):
    block = m.group(0)
    block_hash = sha1(block)
    stored_blocks[block_hash] = block
    return '{{{%s}}}' % block_hash

num_converted = 0
def convert_variables(m):
    name = m.group(1)
    num_converted += 1
    return '<%%= %s %%>' % name

fixed = MATCH_DECLARE_NEW.sub('', template)
fixed = MATCH_PYTHON_BLOCK.sub(replace_blocks, fixed)
fixed = MATCH_FORMAT.sub(convert_variables, fixed)

Adding elements to stored_blocks works fine, but I cannot increase num_converted in the second subfunction:

UnboundLocalError: local variable 'num_converted' referenced before assignment

I could use global but global variables are ugly and I really don't need that variable to be global at all.

So I'm curious how I can write to a variable in the parent function's scope. nonlocal num_converted would probably do the job, but I need a solution that works with Python 2.x.


Problem: This is because Python's scoping rules are demented. The presence of the += assignment operator marks the target, num_converted, as local to the enclosing function's scope, and there is no sound way in Python 2.x to access just one scoping level out from there. Only the global keyword can lift variable references out of the current scope, and it takes you straight to the top.

Fix: Turn num_converted into a single-element array.

num_converted = [0]
def convert_variables(m):
    name = m.group(1)
    num_converted[0] += 1
    return '<%%= %s %%>' % name

(see below for the edited answer)

You can use something like:

def convert_variables(m):
    name = m.group(1)
    convert_variables.num_converted += 1
    return '<%%= %s %%>' % name

convert_variables.num_converted = 0

This way, num_converted works as a C-like "static" variable of the convert_variable method


(edited)

def convert_variables(m):
    name = m.group(1)
    convert_variables.num_converted = convert_variables.__dict__.get("num_converted", 0) + 1
    return '<%%= %s %%>' % name

This way, you don't need to initialize the counter in the main procedure.