Or Halimi
Or Halimi

Reputation: 671

local variable referenced before assignment in python when i set it global

from random import randint
shifts = [4, 4.2, 5, 6, 7]
days_names = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday']
workers_names = ['Itai', 'Or', 'Reut', 'Kuka', 'Aviel']
counter = 1

def shift_arrange(worker):
    for day in days.values():
        counter+=1
        global avilable_shifts
        avilable_shifts = check_avilable_shifts(day)
        if not random_shifte_selector(worker,day): soft_reset(worker)

I set counter as a global variable, and when i try to run this code i get the local variable error:

Traceback (most recent call last):
  File "C:\Or\mypy\shift creator\shift cretor.py", line 144, in <module>
    for w in workers.values(): shift_arrange(w)
  File "C:\Or\mypy\shift creator\shift cretor.py", line 105, in shift_arrange
    counter+=1
UnboundLocalError: local variable 'counter' referenced before assignmen

I saw some guy ask this question here, he deleted his pyc file or something(i don't know what is it) and its work fine. Why this is happen? Its not happen to other variables in the program.

Thanks, Or

Upvotes: 2

Views: 6223

Answers (2)

Corley Brigman
Corley Brigman

Reputation: 12391

There's a lot to look up here, but in general python has names, and things that are assigned to them. The name could be either in the local or global scope.

For reads, python looks through local scope, then through global scope, and uses the first one it finds (or error if it doesn't).

For writes... python needs to know where to put it. Normally, what it would do is look in the local scope, and if it's not there, create a variable there and assign the value. This would hide the global variable. You could have it also look in globals and use that one if it exists - but that could be undesirable & unexpected. So, you need a way to tell python to use a global variable instead if it exists (and then, it will create if it doesn't).

This leads to some odd behaviour sometimes as well. In addition to the earlier answer...

c = 0

# Passes. We are just looking up the global variable.
def f1(x):
    return x + c

# Passes, but may not be as expected. Sets a local variable c to a value, does not 
# modify the global one.
def f2(x):
    c = x

# Correct way to do the above; now it sets the global variable.
def f3(x):
    global c
    c = x

# What if you mix them?
def f4(x):
    c = c + x
# This fails. What happens is that first it sees that it's writing to c, and it's
# not marked global, so it assigns c to the local space. Then it tries to dereference
# it. Since we've marked it local, it masks the global one, and since it doesn't
# have a value, it throws an error. c += x works the same way and also fails.

# However, this works, though is just as equally wrong:
def f5(x):
    d = c
    c = d + x
# This one works, because we copy the value of the global c into the local d.
# Then, the second line assigns a local c to addition of local d and x. 
# But does not update the global.

# Each line is separate though:
def f6(x):
    d = c
    c = c + 1
# You might think that d=c already made c local for the whole function. But it doesn't
# work like that. The first line just looks up the value for c, which it finds
# globally, but then forgets about it - it cares about the object c is the name of,
# not the name c itself. The second line still fails.

Upvotes: 1

shx2
shx2

Reputation: 64318

You need to declare a global variable

def shift_arrange(worker):
    global counter
    for day in days.values():
        counter+=1
        ...

Since you modify counter in that scope, python treats it as a local variable, unless you declare it as global. If you only need to read it, that isn't necessary.

Consider the following:

This works:

c = 0
def f():
   print c
f()

While this does not:

c = 0 
def f():
  print c
  c = 1
f()

While this does:

c = 0
def f():
  global c
  print c
  c = 1
f()
print c  # prints 1, f() modified the global value

Upvotes: 6

Related Questions