isPrime works but UnBoundLocalError when mapping on list

D

defn noob

isPrime works when just calling a nbr but not when iterating on a
list, why? adding x=1 makes it work though but why do I have to add
it?
Is there a cleaner way to do it?


def isPrime(nbr):
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False
[isPrime(y) for y in range(11)]

Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
[isPrime(y) for y in range(11)]
File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment


Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
map(isPrime, range(100))
File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignmentTrue



adding x=1 makes it work though:

def isPrime(nbr):
x=1
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False

[isPrime(y) for y in range(11)]
[False, True, True, True, False, True, False, True, False, False,
False]
 
N

norseman

defn said:
isPrime works when just calling a nbr but not when iterating on a
list, why? adding x=1 makes it work though but why do I have to add
it?
Is there a cleaner way to do it?


def isPrime(nbr):
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False
[isPrime(y) for y in range(11)]

Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
[isPrime(y) for y in range(11)]
File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment


Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
map(isPrime, range(100))
File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignmentTrue



adding x=1 makes it work though:

def isPrime(nbr):
x=1
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False

[isPrime(y) for y in range(11)]
[False, True, True, True, False, True, False, True, False, False,
False]

========================================
Yep - "local variable 'x' referenced before assignment" is correct.
You state: for x in range... but x doesn't exist until initialized.
To save a loop, initialize x=2 (the minimum value) and loop executes
on pass one.
In a straight 'C' program
( for (x=1, x=(nbr+1), x++) etc... )
the x is initialized and forceably incremented.
seems Python does not auto initialize but does auto increment.


Steve
(e-mail address removed)
 
A

Andreas Tawn

defn said:
isPrime works when just calling a nbr but not when iterating on a
list, why? adding x=1 makes it work though but why do I have to add
it?
Is there a cleaner way to do it?


def isPrime(nbr):
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False
[isPrime(y) for y in range(11)]

Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
[isPrime(y) for y in range(11)]
File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment

map(isPrime, range(100))

Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
map(isPrime, range(100))
File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment
isPrime(10) False
isPrime(11)
True



adding x=1 makes it work though:

def isPrime(nbr):
x=1
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False

[isPrime(y) for y in range(11)]
[False, True, True, True, False, True, False, True, False, False,
False]

========================================
Yep - "local variable 'x' referenced before assignment" is correct.
You state: for x in range... but x doesn't exist until initialized.
To save a loop, initialize x=2 (the minimum value) and loop executes
on pass one.
In a straight 'C' program
( for (x=1, x=(nbr+1), x++) etc... )
the x is initialized and forceably incremented.
seems Python does not auto initialize but does auto increment.

I think a better explanation is that in your original function, x only
existed while the for loop was running. As soon as execution hit the
break statement, x ceased to exist. When you attempted to reference it
in the next line, Python has no variable called x so it complains that x
hasn't been initialised.

A more idiomatic way to write it...

def isPrime(nbr):
if nbr <= 1:
return False
for x in xrange(2, nbr+1):
if not nbr % x:
return x == nbr

Cheers,

Drea
 
M

Mensanator

isPrime works when just calling a nbr but not when iterating on a
list, why? adding x=1 makes it work though but why do I have to add
it?
Is there a cleaner way to do it?

def isPrime(nbr):
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False
[isPrime(y) for y in range(11)]

Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    [isPrime(y) for y in range(11)]
  File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
    if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment

Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    map(isPrime, range(100))
  File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
    if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment>>> isPrime(10)
False
True

adding x=1 makes it work though:

def isPrime(nbr):
    x=1
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False
[isPrime(y) for y in range(11)]

[False, True, True, True, False, True, False, True, False, False,
False]

No, it doesn't. You are falsely reporting that 1 is prime.

And instead of making the fake variable x, shouldn't you
instead test that nbr+1 is greater than 2? Or call it with
range(3,11) instead of range(11)? x isn't initialized
because if nbr+1 is <=2, the for loop has an invalid range
and doesn't even execute.
 
D

defn noob

isPrime works when just calling a nbr but not when iterating on a
list, why? adding x=1 makes it work though but why do I have to add
it?
Is there a cleaner way to do it?
def isPrime(nbr):
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False
[isPrime(y) for y in range(11)]
Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    [isPrime(y) for y in range(11)]
  File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
    if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment
map(isPrime, range(100))
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    map(isPrime, range(100))
  File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
    if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment>>> isPrime(10)
False

adding x=1 makes it work though:
def isPrime(nbr):
    x=1
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False
[isPrime(y) for y in range(11)]
[False, True, True, True, False, True, False, True, False, False,
False]

No, it doesn't. You are falsely reporting that 1 is prime.

And instead of making the fake variable x, shouldn't you
instead test that nbr+1 is greater than 2? Or call it with
range(3,11) instead of range(11)? x isn't initialized
because if nbr+1 is <=2, the for loop has an invalid range
and doesn't even execute.


def isPrime(nbr):
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False

this works for all primes, if i want to not include 1 i just do if
nbr<=1 return false

you are answering the wrong question.


anyway here is a clear one:
def isPrime(nbr):
if nbr < 2:
return False
for x in range(2, nbr + 1):
if nbr % x == 0:
return nbr == x
 
M

Mensanator

defn said:
isPrime works when just calling a nbr but not when iterating on a
list, why? adding x=1 makes it work though but why do I have to add
it?
Is there a cleaner way to do it?
def isPrime(nbr):
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False
[isPrime(y) for y in range(11)]
Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    [isPrime(y) for y in range(11)]
  File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
    if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment
map(isPrime, range(100))
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    map(isPrime, range(100))
  File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
    if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment
isPrime(10)
False
isPrime(11)
True
adding x=1 makes it work though:
def isPrime(nbr):
    x=1
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False
[isPrime(y) for y in range(11)]
[False, True, True, True, False, True, False, True, False, False,
False]
========================================
Yep - "local variable 'x' referenced before assignment" is correct.
You state: for x in range... but x doesn't exist until initialized.
  To save a loop, initialize x=2 (the minimum value) and loop executes
  on pass one.
In a straight 'C' program
  (  for (x=1, x=(nbr+1), x++)  etc...  )
  the x is initialized and forceably incremented.
  seems Python does not auto initialize but does auto increment.

I think a better explanation is that in your original function, x only
existed while the for loop was running.

The for loop never ran.
As soon as execution hit the break statement,

It never hit the break statement, the first call from
[isPrime(y) for y in range(11)]
attempted to do for x in range(2,1).
x ceased to exist.

Something has to exist before it can cease to exist.
When you attempted to reference it
in the next line, Python has no variable called x so it complains that x
hasn't been initialised.

Right conlusion but false premise.
 
M

Mensanator

isPrime works when just calling a nbr but not when iterating on a
list, why? adding x=1 makes it work though but why do I have to add
it?
Is there a cleaner way to do it?
def isPrime(nbr):
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False
[isPrime(y) for y in range(11)]
Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    [isPrime(y) for y in range(11)]
  File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
    if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment
map(isPrime, range(100))
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    map(isPrime, range(100))
  File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
    if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment>>> isPrime(10)
False
isPrime(11)
True
adding x=1 makes it work though:
def isPrime(nbr):
    x=1
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False
[isPrime(y) for y in range(11)]
[False, True, True, True, False, True, False, True, False, False,
False]
No, it doesn't. You are falsely reporting that 1 is prime.
And instead of making the fake variable x, shouldn't you
instead test that nbr+1 is greater than 2? Or call it with
range(3,11) instead of range(11)? x isn't initialized
because if nbr+1 is <=2, the for loop has an invalid range
and doesn't even execute.

def isPrime(nbr):
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            break
    if x == nbr:
        return True
    else:
        return False

this works for all primes, if i want to not include 1 i just do if
nbr<=1 return false

you are answering the wrong question.

No, I also mentioned the for loop having an invalid range,
which is why your original failed.

Pointing out that 1 isn't prime was a bonus.
anyway here is a clear one:
def isPrime(nbr):
    if nbr < 2:
        return False
    for x in range(2, nbr + 1):
        if nbr % x == 0:
            return nbr == x

I suppose you're not interested in knowing you don't
have to test anything higher than the square root of
the number.
 
N

norseman

Mensanator said:
isPrime works when just calling a nbr but not when iterating on a
list, why? adding x=1 makes it work though but why do I have to add
it?
Is there a cleaner way to do it?
def isPrime(nbr):
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False
[isPrime(y) for y in range(11)]
Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
[isPrime(y) for y in range(11)]
File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment
map(isPrime, range(100))
Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
map(isPrime, range(100))
File "C:\Python25\Progs\blandat\myMath.py", line 9, in isPrime
if x == nbr:
UnboundLocalError: local variable 'x' referenced before assignment>>> isPrime(10)
False
isPrime(11)
True
adding x=1 makes it work though:
def isPrime(nbr):
x=1
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False
[isPrime(y) for y in range(11)]
[False, True, True, True, False, True, False, True, False, False,
False]
No, it doesn't. You are falsely reporting that 1 is prime.
And instead of making the fake variable x, shouldn't you
instead test that nbr+1 is greater than 2? Or call it with
range(3,11) instead of range(11)? x isn't initialized
because if nbr+1 is <=2, the for loop has an invalid range
and doesn't even execute.
def isPrime(nbr):
for x in range(2, nbr + 1):
if nbr % x == 0:
break
if x == nbr:
return True
else:
return False

this works for all primes, if i want to not include 1 i just do if
nbr<=1 return false

you are answering the wrong question.

No, I also mentioned the for loop having an invalid range,
which is why your original failed.

Pointing out that 1 isn't prime was a bonus.
anyway here is a clear one:
def isPrime(nbr):
if nbr < 2:
return False
for x in range(2, nbr + 1):
if nbr % x == 0:
return nbr == x

I suppose you're not interested in knowing you don't
have to test anything higher than the square root of
the number.
===========================
"don't...test...higher than the square root..."

I wondered when that was going to show up.
I too had a good math teacher.

Steve
(e-mail address removed)
 
T

Terry Reedy

Andreas said:
I think a better explanation is that in your original function, x only
existed while the for loop was running. As soon as execution hit the
break statement, x ceased to exist.

Wrong. For loop variables continue after the loop exits. This is
intentional. Mensanator gave the correct explanation (loop never enters
for nbr==1).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,122
Latest member
VinayKumarNevatia_
Top