4

I am learning Python. A book on Python 3 says the following code should work fine:

def funky():
    print(myvar)
    myvar = 20
    print(myvar)

myvar = 10
funky()

But when I run it in Python 3.3, I got the

UnboundLocalError: local variable 'myvar' referenced before assignment

error. My understanding is that the first print(myvar) in funky should be 10 since it's a global variable. The second print(myvar) should be 20 since a local myvar is defined to be 20. What is going on here? Please help clarify.

David Robinson
  • 77,383
  • 16
  • 167
  • 187
JACKY88
  • 3,391
  • 5
  • 32
  • 48
  • possible duplicate of [local var referenced before assignment](http://stackoverflow.com/questions/8934772/local-var-referenced-before-assignment) – David Robinson Jan 20 '13 at 04:48
  • 2
    While the duplicate answers your question, the simplest answer is that you can add `global myvar` at the start of the function if you want to treat it as a global variable. If you ever assign to `myvar` in the function (as you do in the line `myvar = 20`), Python assumes it is a local variable and thinks you are referring to it before it is defined. – David Robinson Jan 20 '13 at 04:50
  • @DavidRobinson Is this `global` new in Python 3.3 since that book didn't mention it? – JACKY88 Jan 20 '13 at 04:58
  • 1
    No, `global` has been around for a while. Are you sure that the book wasn't giving this as an example of code that *didn't* work? – David Robinson Jan 20 '13 at 04:59
  • @DavidRobinson No. The book is at [here](http://inventwithpython.com/IYOCGwP_book1.pdf). The bottom of page 66. – JACKY88 Jan 20 '13 at 05:06
  • possible duplicate of [Using global variables in a function other than the one that created them](http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them) – Frank Shearar Jan 20 '13 at 09:50

3 Answers3

8

You need to call global in your function before assigning a value.

def funky():
    global myvar
    print(myvar)
    myvar = 20
    print(myvar)

myvar = 10
funky()

Note that you can print the value without calling global because you can access global variables without using global, but attempting to assign a value will require it.

mgoffin
  • 755
  • 6
  • 12
2

From the docs:

Each occurrence of a name in the program text refers to the binding of that name established in the innermost function block containing the use.

It means that unless you declare it global or nonlocal (nested functions) then myvar is a local variable or a free variable (if myvar is not defined in the function).

The book is incorrect. Within the same block the name represents the same variable (local variable myvar in your example, you can't use it until you define it even if there is a global variable with the same name). Also you can change values outside a function i.e., the text at the end of page 65 is also incorrect. The following works:

def funky(): # local
    myvar = 20 
    print(myvar) # -> 20
myvar = 10 # global and/or local (outside funky())
funky()
print(myvar) # -> 10 (note: the same)

 

def funky(): # global
    global myvar
    print(myvar) # -> 10
    myvar = 20
myvar = 10
funky() 
print(myvar) # -> 20 (note: changed)

 

def funky(): # free (global if funky is not nested inside an outer function)
    print(myvar) # -> 10
myvar = 10
funky() 

 

def outer():
    def funky():  # nonlocal
        nonlocal myvar
        print(myvar) # -> 5
        myvar = 20
    myvar = 5 # local
    funky()
    print(myvar) # -> 20 (note: changed)
outer()
jfs
  • 399,953
  • 195
  • 994
  • 1,670
0

Python "assumes" that we want a local variable due to the assignment to myvar inside of funky(), so the first print statement throws ## UnboundLocalError: local variable 'myvar' referenced before assignment ## error message. Any variable which is changed or created inside of a function is local, if it hasn't been declared as a global variable. To tell Python, that we want to use the global variable, we have to use the keyword "global", as can be seen in the following example:

def f():
  global s
  print s
  s = "That's clear."
  print s 


s = "Python is great!" 
f()
print s
jack
  • 505
  • 2
  • 7