Search code examples
pythonvariableslocal

assigned variable gets 'UnboundLocalError'


UnboundLocalError: local variable 'i' referenced before assignment. That is the error I got from my code, but my 'i' is in local range still.

the fuction factor2(n) works by itself. but when put in a for loop, it throw the error. I know there is something behind this, but I can not figure out.

def tri_num(n):
    return n * (n + 1) // 2


def factors2(n):
    f_ = 1
    for i in range(2, int(n ** .5) + 1):
        count_ = 0
        while n % i == 0:
            count_ += 1
            n /= i
        if count_ != 0:
            f_ *= count_ + 1
    else:
        if n > i:
            f_ *= 2
    return f_


import itertools
for n in itertools.count(1):
    m = tri_num(n)
    q= factors2(m)
    if q > 500:
        print(m,q)
        break


*

---------------------------------------------------------------------------
    UnboundLocalError                         Traceback (most recent call last)
    <ipython-input-52-07bebaa60ddd> in <module>()
          2 for n in itertools.count(1):
          3     m = tri_num(n)
    ----> 4     q= factors2(m)
          5     if q > 500:
          6         print(m,q)

    <ipython-input-51-214ce9ab60ad> in factors2(n)
          9             f_ *= count_ + 1
         10     else:
    ---> 11         if n > i:
         12             f_ *= 2
         13     return f_

    UnboundLocalError: local variable 'i' referenced before assignment

*

'else:' is part of the for loop, it should not throw an error

s = factors2(81)
print(s)

give me my answer '5', no error for that.

my script should work and give me two numbers

UPDATE: Thank you, I figured out. It is a bug in my factors2(), it fail to function when n = 0, 1 and 2. it will be fixed


Solution

  • You are iterating over an empty range, which means i is never assigned to before you enter the for loop's else clause.

    For instance, the first value yielded by count is 1. Then tri_num(1) == 1, so factors2 gets called with n == 1. This results in a call to range(2, int(1**.5)+1), which results in range(2,2) which is indeed empty. Since the iterator never yields a value, i is never assigned to, and the else clause is entered, where you assume i does have a value. QED.