74

I was just trying to see how variable scopes work and ran into the following situation (all ran from the terminal):

x = 1
def inc():
    x += 5

inc()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in inc
UnboundLocalError: local variable 'x' referenced before assignment

I was thinking maybe I don't have access to x in my method, so I tried:

def inc():
    print(x)

1

So this works. Now I know I could just do:

 def inc():
     global x
     x += 1

And this would work, but my question is why does the first example fail? I mean I would expect since print(x) worked that x is visible inside the function so why would the x += 5 fail?

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Bogdan
  • 8,017
  • 6
  • 48
  • 64
  • 1
    Less then 24 hours ago someone asked a [very similar question](http://stackoverflow.com/q/8934772/1132524), maybe you want to take a look. – Rik Poggi Jan 20 '12 at 15:45
  • Everybody is complicating matter more than necessary, while missing the most important *feature* of using `global`. Namely that you can define a variable `x` **after** the function definition, and then still use/access it inside that function with `global x`. – not2qubit Nov 27 '20 at 17:22
  • In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be local unless explicitly declared as global. For further details refer to this link: http://docs.python.org/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value – BOT_bkcd May 25 '21 at 11:27

3 Answers3

65

Unlike languages that employ 'true' lexical scoping, Python opts to have specific 'namespaces' for variables, whether it be global, nonlocal, or local. It could be argued that making developers consciously code with such namespaces in mind is more explicit, thus more understandable. I would argue that such complexities make the language more unwieldy, but I guess it's all down to personal preference.

Here are some examples regarding global:-

>>> global_var = 5
>>> def fn():
...     print(global_var)
... 
>>> fn()
5
>>> def fn_2():
...     global_var += 2
...     print(global_var)
... 
>>> fn_2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fn_2
UnboundLocalError: local variable 'global_var' referenced before assignment
>>> def fn_3():
...     global global_var
...     global_var += 2
...     print(global_var)
... 
>>> fn_3()
7

The same patterns can be applied to nonlocal variables too, but this keyword is only available to the latter Python versions.

In case you're wondering, nonlocal is used where a variable isn't global, but isn't within the function definition it's being used. For example, a def within a def, which is a common occurrence partially due to a lack of multi-statement lambdas. There's a hack to bypass the lack of this feature in the earlier Pythons though, I vaguely remember it involving the use of a single-element list...

Note that writing to variables is where these keywords are needed. Just reading from them isn't ambiguous, thus not needed. Unless you have inner defs using the same variable names as the outer ones, which just should just be avoided to be honest.

Louis
  • 2,442
  • 1
  • 18
  • 15
  • 2
    In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be local unless explicitly declared as global. For further information refer to this link: http://docs.python.org/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value – BOT_bkcd May 25 '21 at 11:28
40

When Python parses a function, it notes when a variable assignment is made. When there is an assignment, it assumes by default that that variable is a local variable. To declare that the assignment refers to a global variable, you must use the global declaration.

When you access a variable in a function, its value is looked up using the LEGB scoping rules.


So, the first example

x = 1
def inc():
    x += 5
inc()

produces an UnboundLocalError because Python determined x inside inc to be a local variable,

while accessing x works in your second example

def inc():
    print x

because here, in accordance with the LEGB rule, Python looks for x in the local scope, does not find it, then looks for it in the extended scope, still does not find it, and finally looks for it in the global scope successfully.

Neuron
  • 5,141
  • 5
  • 38
  • 59
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 3
    In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be local unless explicitly declared as global. For further information refer to this link: http://docs.python.org/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value – BOT_bkcd May 25 '21 at 11:28
10

The local names for a function are decided when the function is defined:

>>> x = 1
>>> def inc():
...     x += 5
...     
>>> inc.__code__.co_varnames
('x',)

In this case, x exists in the local namespace. Execution of x += 5 requires a pre-existing value for x (for integers, it's like x = x + 5), and this fails at function call time because the local name is unbound - which is precisely why the exception UnboundLocalError is named as such.

Compare the other version, where x is not a local variable, so it can be resolved at the global scope instead:

>>> def incg():
...    print(x)
...    
>>> incg.__code__.co_varnames
()

Similar question in faq: http://docs.python.org/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value

wim
  • 338,267
  • 99
  • 616
  • 750