Python scope when assignment never performed

Viewed 60

So I get that

x = 5
def f():
    print(x)

f()
print(x)

gives back 5 and 5.

I also get that

x = 5
def f():
    x = 7
    print(x)

f()
print(x)

gives back 7 and 5.

What is wrong with the following?

x = 5
def f():
    if False:
        x = 7   
        print(x)
    else:
        print(x)

f()
print(x)

I would guess that since the x=7 never happens I should get 5 and 5 again. Instead I get

UnboundLocalError: local variable 'x' referenced before assignment

Does python regard x as a local variable because in this indented block there is an assignment expression regardless if it is executed or not? What is the rule exactly?

3 Answers

When the function is defined python interprets x as a local variable since it's assigned inside the body of the function. During runtime, when you go into the else clause, the interpreter looks for a local variable x, which is unassigned.

If you want both x to refer to the same variable, you can add global x inside the body of the function, before its assignment to essentially tell python when I call x I'll be referring to the global-scope x.

If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.

You need to use global in your function f() like so:

x = 5
def f():
    global x
    if False:
        x = 7   
        print(x)
    else:
        print(x)

f()
print(x)
Related