370

The following code gives the error UnboundLocalError: local variable 'Var1' referenced before assignment:

Var1 = 1
Var2 = 0
def function(): 
    if Var2 == 0 and Var1 > 0:
        print("Result 1")
    elif Var2 == 1 and Var1 > 0:
        print("Result 2")
    elif Var1 < 1:
        print("Result 3")
    Var1 -= 1
function()

How can I fix this?

Community
  • 1
  • 1
Eden Crow
  • 14,684
  • 11
  • 26
  • 24
  • 2
    Notice that it will work if you use `dic = {'Var1':1, 'Var2':0}` and access Var1 and Var2 through the dictionary. – xslittlegrass Aug 10 '17 at 05:07
  • 10
    Beside the point, but `Var1 =- 1` is parsed as `Var1 = -1`, not `Var1 -= 1` – wjandrea Mar 31 '20 at 17:54
  • How comes doesn't give error UnboundLocalError: local variable 'Var2' referenced before assignment? Even when you change if Var2 == 0 and Var1 > 0: to if Var2 == 0: – chikitin Sep 11 '20 at 17:34
  • 3
    @chikitin It doesn't give error for Var2 because in your function you have no where assigned any value to Var2, because of which it considers the global value of Var2 by default. But since, you have mentioned Var1=- 1 which python interprets as Var1 = -1, it considers that Var1 is assigned a local value and hence Var1 becomes a local & a global variable, which python considers separate. Since this assignment of Var1 comes after using Var1 in the same function, we get this reference before assignment error. Hope this gives some clarity – Sugandha Jain Dec 14 '20 at 16:13
  • @chikitin Just in case, if you want to pop error for Var2 as well just to check and clarify your doubt, just assign some value to Var2 as well below Var1=-1 statement and then you'll get error for Var2 as well. – Sugandha Jain Dec 14 '20 at 16:16
  • I have same problem, i used dictionary `dic = {'Var1':1, 'Var2':0}` – Mostafa Apr 21 '21 at 04:26
  • keep outside variable initialization as it is and inside function first define global Var1,Var2 reference link : https://www.techgeekbuzz.com/python-local-variable-referenced-before-assignment-solution/ – jay sedani Dec 24 '21 at 07:38
  • As @Sugandha pointed out, Var1 and Var2 were used/referenced as global variables until the last assignment statement of Var1 = -1, where it tried to declare a local variable Var1 and found that it has already been referenced as a global variable, hence a conflict resulted. It is essentially like this code: `v = 1; def f(): v = v - 1; f()` To fix it, just use a pass-in `v = 1; def f(v): v = v - 1; f(v)` – Leon Chang Apr 29 '22 at 22:48
  • A good explanation can be found here: [global-local-and-nonlocal-variables-in-python](https://towardsdatascience.com/global-local-and-nonlocal-variables-in-python-6b11c20d73b0) – Matt Oct 27 '22 at 08:56

5 Answers5

721

This is because, even though Var1 exists, you're also using an assignment statement on the name Var1 inside of the function (Var1 -= 1 at the bottom line). Naturally, this creates a variable inside the function's scope called Var1 (truthfully, a -= or += will only update (reassign) an existing variable, but for reasons unknown (likely consistency in this context), Python treats it as an assignment). The Python interpreter sees this at module load time and decides (correctly so) that the global scope's Var1 should not be used inside the local scope, which leads to a problem when you try to reference the variable before it is locally assigned.

Using global variables, outside of necessity, is usually frowned upon by Python developers, because it leads to confusing and problematic code. However, if you'd like to use them to accomplish what your code is implying, you can simply add, inside the top of your function:

global Var1, Var2

This will tell Python that you do not intend to define a Var1 or Var2 variable inside the function's local scope. The Python interpreter sees this at module load time and decides (correctly so) to look up any references to the aforementioned variables in the global scope.

Some Resources

  • the Python website has a great explanation for this common issue.
  • Python 3 offers a related nonlocal statement - check that out as well.
orokusaki
  • 55,146
  • 59
  • 179
  • 257
  • 9
    @user7344209 Indeed. Answers should ideally explain what's happening in the actual example shown, and how to fix that, rather than suggesting a whole different approach. – Stephen Holt Sep 19 '18 at 20:58
  • 6
    "Naturally", it does not seem natural to me. – dumbledad Jan 03 '20 at 10:04
  • @dumbledad I only mean “naturally” in the sense that `+=` is an assignment operator (`iadd`, which stands for “in-place add”) – orokusaki Jan 03 '20 at 15:16
  • 6
    Nicely explained with a workable solution – Anant Tyagi Feb 11 '20 at 06:50
  • What is the process that is to blame for this kind of phenomenon? I'd like to look into if other languages do something similar but I'm not sure what to google. – lightbox142 Aug 15 '20 at 19:36
166

If you set the value of a variable inside the function, python understands it as creating a local variable with that name. This local variable masks the global variable.

In your case, Var1 is considered as a local variable, and it's used before being set, thus the error.

To solve this problem, you can explicitly say it's a global by putting global Var1 in you function.

Var1 = 1
Var2 = 0
def function():
    global Var1
    if Var2 == 0 and Var1 > 0:
        print("Result One")
    elif Var2 == 1 and Var1 > 0:
        print("Result Two")
    elif Var1 < 1:
        print("Result Three")
    Var1 =- 1
function()
madjar
  • 12,691
  • 2
  • 44
  • 52
103

You can fix this by passing parameters rather than relying on Globals

def function(Var1, Var2): 
    if Var2 == 0 and Var1 > 0:
        print("Result One")
    elif Var2 == 1 and Var1 > 0:
        print("Result Two")
    elif Var1 < 1:
        print("Result Three")
    return Var1 -= 1
function(1, 1)
MattDMo
  • 100,794
  • 21
  • 241
  • 231
Jakob Bowyer
  • 33,878
  • 8
  • 76
  • 91
14

I don't like this behavior, but this is how Python works. The question has already been answered by others, but for completeness, let me point out that Python 2 has more such quirks.

def f(x):
    return x

def main():
    print f(3)
    if (True):
        print [f for f in [1, 2, 3]]

main()

Python 2.7.6 returns an error:

Traceback (most recent call last):
  File "weird.py", line 9, in <module>
    main()
  File "weird.py", line 5, in main
    print f(3)
UnboundLocalError: local variable 'f' referenced before assignment

Python sees the f is used as a local variable in [f for f in [1, 2, 3]], and decides that it is also a local variable in f(3). You could add a global f statement:

def f(x):
    return x

def main():
    global f
    print f(3)
    if (True):
        print [f for f in [1, 2, 3]]

main()

It does work; however, f becomes 3 at the end... That is, print [f for f in [1, 2, 3]] now changes the global variable f to 3, so it is not a function any more.

Fortunately, it works fine in Python3 after adding the parentheses to print.

Sergey Orshanskiy
  • 6,794
  • 1
  • 46
  • 50
5

Why not simply return your calculated value and let the caller modify the global variable. It's not a good idea to manipulate a global variable within a function, as below:

Var1 = 1
Var2 = 0

def function(): 
    if Var2 == 0 and Var1 > 0:
        print("Result One")
    elif Var2 == 1 and Var1 > 0:
        print("Result Two")
    elif Var1 < 1:
        print("Result Three")
    return Var1 - 1

Var1 = function()

or even make local copies of the global variables and work with them and return the results which the caller can then assign appropriately

def function():
v1, v2 = Var1, Var2
# calculate using the local variables v1 & v2
return v1 - 1

Var1 = function()
chancyWu
  • 14,073
  • 11
  • 62
  • 81
ctx
  • 79
  • 1
  • 2