2

I used to program in C, C# and Java. Now I'm using Python for a while but I encountered some problems with understanding variable scope which is quite confusing for me right now. For example:

def f1():
    print(spam)   # spam magically come from outer scope. ok...


def f2():
    spam = "bbb"  # assignment shadows variable from outer scope (logical result of f1)
    print(spam)   # printing local spam variable


def f3():
    print(spam)   # ERROR: unresolved reference 'spam'
    spam = "ccc"  # in f1 function everything was fine but adding assignment AFTER
                  # printing (in opposite to f2 function) causes error in line above


def f4():
    print(spam)   # nothing wrong here, assignment line below is commented
    # spam = "ccc"

spam = "aaa"

Why on earth functions can reach variables outside their scope? And why shadowing variable from outer scope is ok but only if we didn't use it before?

user3616181
  • 975
  • 2
  • 8
  • 27

1 Answers1

2

Python code is compiled to byte code before execution. This means Python can analyze how the function uses variables. A variable is either global or local in a function but not both and it cannot change.

spam is global in f1 because it is never assigned. spam is local in f2 because it is assigned. The same goes for f3. spamis local in f3 because of spam='ccc'. With the print(spam) statement you try to access the local variable before it was assigned.

You can use global spam inside a function to forcefully declare a variable name as global.

Local stays local. Even after deleting a variable in the local namespace Python does not look up the name in the parent scope:

spam = 123

def f():
    spam = 42
    print(spam)  # 42
    del spam
    print(spam)  # UnboundLocalError

f()

If you want to assign a global variable you need to declare it:

spam = 123

def f():
    global spam
    spam = 42
    print(spam)  # 42

f()
print(spam)  # 42
MB-F
  • 22,770
  • 4
  • 61
  • 116
  • Oh, I forgot that even many people say that python is interpreted right from the script it in fact has compilation phase. – user3616181 Feb 23 '17 at 15:29
  • But why functions can reach outer variables? What's the idea behind this? Because someone had to come to conclusion that it's a desirable behavior – user3616181 Feb 23 '17 at 15:33
  • @user3616181 Because in Python there is no difference between variables, functions, and other objects. You want to be able to call `print` inside your function definition, don't you? `print` is a global object and so is `spam`. `spam` could also be a function that you want to call inside your other function. There is simply no reason not to allow global lookup. I once thought about disabling this feature, but this turned out to be a [bad idea](http://stackoverflow.com/a/31023487/3005167). – MB-F Feb 23 '17 at 15:38
  • Knowing that "in Python there is no difference between variables, functions, and other objects" the situation is clear. In other languages I used there was a significant difference between functions and variables. You could call function outside your scope but you couldn't use such variables. That's why I was so confused. Thanks for clearing it out. – user3616181 Feb 23 '17 at 16:04