2
x = 1
def fn():
    print x
fn()

This prints "1":

x = 1
def fn():
    x += 1
    print x
fn()

This raises "UnboundLocalError: local variable 'x' referenced before assignment"

What is going on here?

cammil
  • 9,499
  • 15
  • 55
  • 89

4 Answers4

4

In Python, assigning to a variable is also an implicit local declaration, that is resolved during the bytecode compilation. So

x += 1

will create a local variable x and compile to this byte code:

0 LOAD_FAST                0 (x)
3 LOAD_CONST               1 (1)
6 INPLACE_ADD
7 STORE_FAST               0 (x)

The command LOAD_FAST will try to load a local variable x which is not yet defined, that's why it fails.

However, if you define x as global explicitly, then it will use LOAD_GLOBAL/STORE_GLOBAL instead.

In the case of print in your first function, the compiler assumes that since no local variable is declared (assigned) ever in the function body, you should mean a global variable.

bereal
  • 32,519
  • 6
  • 58
  • 104
2

The act of assigning to a name, anywhere inside a function, makes that name local only.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
1

You're using a local variable , a different binding, not the global one.

A scope defines the visibility of a name within a block. If a local variable is defined in a block, its scope includes that block. If the definition occurs in a function block, the scope extends to any blocks contained within the defining one, unless a contained block introduces a different binding for the name

Juan Diego Godoy Robles
  • 14,447
  • 2
  • 38
  • 52
0

Because you have to add global x to the function:

def fn():
    global x
    x += 1
    print x

This tells the interpreter that you intend to modify a global variable. This is not necessary for certain objects like mutable sequences (e.g. list).

Community
  • 1
  • 1
TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
  • This still doesn't answers the question! why you can `print` but can't assign? – Mazdak Jul 30 '15 at 08:15
  • The question seems to be asking why the assignment isn't working, to which the answer is "because `global x` is missing," rather than what internal mechanic or design decision led to this state of affairs. – TigerhawkT3 Jul 30 '15 at 08:17
  • If it was so still *because global x* is not a proper answer! – Mazdak Jul 30 '15 at 08:19
  • "It's not a proper answer" tells me neither why it's not a proper answer, nor how I can improve it. – TigerhawkT3 Jul 30 '15 at 08:21
  • Because,you instead of explaining the reason of this error you just suggest a solution which may be not a secure way. This is just like giving fish when you need to learn the fishing! – Mazdak Jul 30 '15 at 08:26
  • The reason is that Python will allow you to access global variables, but you can only modify them if you explicitly state as much. I don't use global variables in my own code, but if someone is using them for their own code and has run into a problem trying to modify them, is it better to clearly explain how to solve the problem (and this is the only answer that actually does that), or just tell them that they should refactor their code to avoid global variables because you don't like them? – TigerhawkT3 Jul 30 '15 at 08:30
  • First of all it's better to add your explanations to your answer, second anything is bad is bad and you need to tell it when you want to suggest it to anybody! – Mazdak Jul 30 '15 at 08:33