2

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?

mr_tuna
  • 185
  • 1
  • 7
  • Python Scope is based on LEGB(Local, Enclosing, Global, and Built-in), there's plenty of articles explaining how it woks. Maybe start here: https://realpython.com/python-scope-legb-rule/ – MShakeG Apr 05 '20 at 00:29
  • Does this answer your question? [Python - reassigning a name inside a function that previously has been looked up in the global scope](https://stackoverflow.com/questions/43231598/python-reassigning-a-name-inside-a-function-that-previously-has-been-looked-up) – andreis11 Apr 06 '20 at 16:59

3 Answers3

4

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.

Djib2011
  • 6,874
  • 5
  • 36
  • 41
2

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.

Bogdan Veliscu
  • 641
  • 6
  • 11
0

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)
Red Cricket
  • 9,762
  • 21
  • 81
  • 166
  • Thanks for the answer! I know how to make it work with the global, I just want to know why on earth would python do this. – mr_tuna Apr 05 '20 at 00:25
  • Check out the docs https://docs.python.org/3/reference/simple_stmts.html#grammar-token-global-stmt or https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces – Red Cricket Apr 05 '20 at 00:26