Python variables scope

By

Understand variable scope in Python and the difference between global and local variables, including why accessing a local variable outside raises a NameError.

~~~

When you declare a variable, that variable is visible in parts of your program, depending on where you declare it. That visibility is what we call scope.

If you declare it outside of any function, the variable is visible to any code running after the declaration, including functions:

age = 8

def test():
    print(age)

print(age) # 8
test() # 8

We call it a global variable.

If you define a variable inside a function, that variable is a local variable, and it is only visible inside that function. Outside the function, it is not reachable:

def test():
    age = 8
    print(age)

test() # 8

print(age)
# NameError: name 'age' is not defined

When the function returns, its local variables are gone. Call the function again and they start fresh.

This is a good thing. A function that only touches its own variables is easier to reason about. You can read it in isolation, without wondering what the rest of the program did to its data.

Reading vs assigning

There’s an asymmetry that trips people up.

Reading a global variable inside a function works, as we saw above. But assigning to a variable inside a function creates a new local variable, even if a global with the same name exists:

count = 0

def increment():
    count = 1 # this is a NEW local variable

increment()
print(count) # 0, the global did not change

The global count stays at 0. The function wrote to its own local count and threw it away.

The UnboundLocalError pitfall

It gets worse when you try to read and assign in the same function:

count = 0

def increment():
    count = count + 1

increment()
# UnboundLocalError: cannot access local variable 'count'
# where it is not associated with a value

Why? Python decides that count is local because the function assigns to it somewhere. Then count + 1 tries to read that local variable before it has a value, and the program crashes.

If you really want to modify the global, declare it with the global keyword:

count = 0

def increment():
    global count
    count = count + 1

increment()
print(count) # 1

My advice is to reach for global rarely. A function that receives values as parameters and returns results is almost always the better design, because you can see everything it depends on right in its signature.

Tagged: Python · All topics
~~~

Related posts about python: