Question on variable scope

Hey guys, as I’ve started to learn Python, there is a situation I’ve come across that I’d like to understand

How come the Python interpreter is able to read the variable var before its declaration in the example 1:

# example 1
def myFunc():
    print("Variable 'var' is", var)
    
var = 1
myFunc()

While in this case, the interpreter throws an UnboundLocalError: local variable 'var' referenced before assignment

# example 2
def myFunc():
    print("Variable 'var' is", var)
    var = 2
    
var = 1
myFunc()

Good question, there was a thread about this recently which you might find interesting: Why does Python have variable hoisting like Javascript?

1 Like

Hello Jose Ricardo Krauss,

You ask:

“How come the Python interpreter is able to read the variable var
before its declaration in the example 1:”

but this is incorrect, the interpreter doesn’t read the variable before
the variable is created because the function isn’t called and executed,
only defined.

Let us follow the interpreter’s steps here. First step is the interpeter
reaches the “def” statement, and prepares a new function object:

def myFunc():
    print("Variable 'var' is", var)

Inside the function, the compiler sees a reference to ‘var’, and it
compiles instructions to look up the global variable ‘var’, but it
doesn’t try to actually look it up yet. If it did, it would fail,
because ‘var’ doesn’t exist yet.

Once the function is compiled and assigned to the name “myFunc”, the
interpreter continues:

var = 1
myFunc()

Here the interpreter assigns the value 1 to the global variable ‘var’
first, then calls ‘myFunc’. So by the time myFunc actually looks
up ‘var’ it has a value assigned.

Now let’s look at your second example:

# Example 2
def myFunc():
    print("Variable 'var' is", var)
    var = 2

Again, the interpreter sees the “def” statement and begins to prepare a
new function object. But this time, the compiler sees a reference to
‘var’, but it knows that it is a local variable, not global. How does
it know that? Because Python follows the rule:

  • If you assign a value to a variable anywhere inside a function, that
    variable is treated as a local variable.

and the compiler sees the line “var = 2”. So it compiles a different set
of instructions to look up the local variable ‘var’ rather than a global
variable ‘var’.

(You can have local variables with the same name as global variables.)

The rest of the process is the same, until it comes to actually calling
myFunc. Inside myFunc, the interpreter tries to look up the value of
‘var’, but it is a local, not a global, and the local var doesn’t have a
value yet – it doesn’t get a value until the next line.

Thanks @lrjball for the suggestion and thanks @steven.daprano for your great reply. There is however still a bit of questioning going on in my mind regarded to the scope of variables.

Okay, I get that this would fix the problem of the Example 2:

# Example 2
def myFunc():
    var = 2
    print("Variable 'var' is", var)
    
var = 1
myFunc()

But what about this code, shouldn’t if fix the problem too?

def myFunc():
    print("Variable 'var' is", var)
    global var
    var = 2
    
var = 1
myFunc()

When I run it, I get a SyntaxError: name 'var' is used prior to global declaration

I thought the global statement would turn any call to local var into global, no matter the position. Apparently, the global statement only works if placed at the first line of the function body.

It used to be that the global declaration could be used anywhere in
the function. But that was changed, and now the global declaration has
to come before the use of the variable. I don’t remember what version
the change was made.

1 Like

Hm, understood. Thank you again @steven.daprano!