python can't access nonlocal variable before local variable is defined with same name
You are more-or-less correct, and you found the correct resolution. Your problem is equivalent to this:
bars = range(10)
def foo():
thing = [x for x in bars]
bars = 'hello'
foo()
# UnboundLocalError: local variable 'bars' referenced before assignment
At function definition time, it is determined that bars
is local scope. And then at function run time, you get the problem that bars hasn't been assigned.
Yes.
Python's scoping rules indicate that a function defines a new scope level, and a name is bound to a value in only one scope level in a scope level—it is statically scoped (i.e. all scoping is determined at compilation time). As you understood, you're trying to violate that by reading from a non-local declaration and writing to a local variable. As you observe, the interpreter objects violently to this by raising an UnboundLocalError
: it has understood that panels
is a local variable (because it can't be that and non-local at the same time), but you haven't assigned (bound) a value to the name, and so it fails.
More technical details
The decision was made in Python to keep track of where variables are at compilation time in the bytecode (to be specific for this case, it's in a tuple get.__code__.co_varnames
for local variables), meaning that a variable can be only used in a single scope level in a certain scope. In Python 2.x, it is not possible to modify a non-local variable; you have either read-only access to a global or non-local variable, or read-write access to a global variable by using the global
statement, or read-write access to a local variable (the default). That's just the way it's been designed (probably for performance and purity). In Python 3, the nonlocal
statement has been introduced with a similar effect to global
, but for an intermediate scope.
Binding the modified variable to a different name is the correct solution in this case.