LordLing
LordLing

Reputation: 331

How does Python handle globals?

I've come across some very odd handling of global variables in Python. I was hoping someone can explain and justify these surprises!

A) This code prints 10 as expected:

def func():
  print(a)
a = 10
func()

B) This code throws an exception about referencing a too early:

def func():
  print(a)
  a += 1
a = 10
func()

C) But this code prints [10] as expected:

def func():
  print(a)
  a.append(1)
a = [10]
func()

So I can gather that the type of a changes its scope and additionally later statements that haven't even been reached yet change how a is seen. I know I can use global a at the start of the function but it's rather verbose.

Can anyone tell me what rules Python is using to handle its bizarre scoping?

Upvotes: 3

Views: 197

Answers (2)

phant0m
phant0m

Reputation: 16905

Basically, there are two rules:

  1. When you only read from a variable (inside a scope), Python will travel up the scope chain until it finds a variable of that name.
  2. When you write to a variable at least once, Python will always create the variable in the current scope.

You can change the behavior of #2, however:

  • If you want a name to refer to a module-level variable, you can use global my_module_variable. When you now write to my_module_variable, Python will not create a local variable.
  • As of Python 3, you can also have a name refer to a variable in an enclosing scope: use nonlocal my_non_local_variable to have it refer to the variable in the nearest enclosing scope.

Problems in your code

B) You are using +=: You are trying to write to the variable. So rule number 2 is in effect, it will write to a variable in the current scope. However, it also has to read from it (print(a)), but the variable does not yet have a value, because you haven't written to it before. Python does not allow you to mix rule 1. and rule 2. in a function.

If you wanted func() to work on the a = 10 variable, you could change your code like this:

>>>> def func()
        global a
        print(a)
        a += 1
>>>> a = 10
>>>> func()
10
>>>> func()
11

Upvotes: 4

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798436

The second instance rebinds a, so the compiler generates a local access for it. The other two only read a, and so normal global scope searching is performed.

Upvotes: 5

Related Questions