This behavior regarding UnboundLocalError
is documented most clearly under the official documentation in the Programming FAQ section, under the heading why am I getting an UnboundLocalError when the variable has a value?. The full behavior regarding this is broadly covered under the "naming and binding" section under "execution model" in the The Python Language Reference manual. Specifically, the following paragraph in section 4.2.2. Resolution of names, fully describes the issue at hand:
When a name is not found at all, a NameError
exception is raised. If the current scope is a function scope, and the name refers to a local variable that has not yet been bound to a value at the point where the name is used, an UnboundLocalError
exception is raised.
As an import inside a function scope (even if hasn't happened yet) will provide an assignment under name
, resulting in local variable name
, and given that it isn't bounded where it gets used (via print
), the UnboundLocalError
will be the result.
As for the "why" - Python does not fully ignore unreachable branches, all code behind if False
blocks are considered by the interpreter, so any assignments to some name within a function block, even if "unreachable", will render the given name a valid local variable (specifically, while the generated bytecode as seen by the disassembler may NOP
out that block, all assignments to some names within will render all those names as entries in co_varnames
).
As an aside, the FAQ entry has been present since Python 2.7 (or perhaps even earlier).