I am new to python and i am still strugling to understand how the sytnax works, how you need to allign your If and else to make it work correctly. How do i really know which else goes with which if? especially when using nested code blocks.
In the code below for the else followed by the comment Prime! from what i understand that else goes with the statement if (n % div == 0): but then why is it alligned with the FOR statement instead?
the last else statement i think goes with if n == 2: but the else is not alligned with it, instead it is after. For the same statement if n == 2: why is n += 1 alligned before pime_count +=1 and not after it.
I understand that the placement of the Else and if is very important because if i decided to move any of them the code stops working. What i can't seem to understand is how does python know which else goes with which if, if the allignment doesnt seem to be consistent.
#!/usr/bin/env python
#
# Problem Set 1a
#
# A program that computes and prints the 1000th prime number.
# Finds primes using trial division (least efficient method)
#------------------------------------------------------------
prime_count = 0
n = 2
while (prime_count <= 1000):
#if even, check for 2, the only even prime
if (n % 2 == 0):
if n == 2:
prime_count += 1
n += 1
else:
# number is odd, possible prime
for div in range(3, n, 2):
if (n % div == 0):
# not a prime
n += 1
break
else:
# prime!
prime_count += 1
if prime_count == 1000:
print "The 1000 prime is", n
else:
n += 1
The rule is very simple: the else clause must have the same indentation as the statement it refers to (most commonly, an if statement).
Now, here:
for div in range(3, n, 2):
if (n % div == 0):
# not a prime
n += 1
break
else:
...
you are not using if-else, you are using for-else!
This construct means "execute the else block unless the loop has terminated through a break".
See for ... else in Python for a discussion.
An if goes with an else at the same indentation, so long as there are no other things at lower indentation between them. They have to be in the same "block". However, in your case, the else that's followed by # prime! is not actually joined to an if at all, but rather to the for div in range(3, n, 2): loop before it!
An else attached to a for loop means "execute this code if the for loop completed without hitting a break statement". It can be useful sometimes, but it is often confusing for people who haven't encountered it before!
I think this can help you to understand how python indentation works http://psung.blogspot.com/2007/12/for-else-in-python.html
In a construct like this one:
for i in foo:
if bar(i):
break
else:
baz()
the else suite is executed after the for, but only if the for terminates normally (not by a break).
In other situations else goes after if
There are 2 rules which are fairly simple,
The indent of the if and else have to be the same
for x in range(15):
if x > 10:
print 'x is more than 10'
else:
print 'x is less than or equal to 10'
Nothing with an indent lower than or equal to that of if and elseshould come in between them
So, this is invalid/ will raise a SyntaxError.
for x in range(15):
if x > 10:
print 'x is more than 10'
print x
else:
print 'x is less than or equal to 10'
Also, As stated in PEP 8
Use 4 spaces per indentation level.
for div in range(3, n, 2):
if (n % div == 0):
# not a prime
n += 1
break
else: # at same indent as for
# prime!
Also, your indent above means for...else loop is made (here else clause is executed if the for loop is exited using break), not if..else.
Related
I am trying to write code to find whether a given number is odd or even using recursion in Python.
When I execute my code, the recursive function descends down to 0 correctly but then doesn't halt, and keeps going with negative values. I expect it to stop when it reaches 0.
How to make sure the function returns after it reaches zero?
My code:
def odeven(n):
if n%2 == 0:
print("even no. : ",n)
elif n%2 != 0:
print("odd no. : ",n)
elif (n == 0):
return 0
return odeven(n-1)
result = odeven(10)
print("result odd ={}".format(result))
Fixing the most obvious mistake
Your main issue is that the branch elif (n == 0): will never be reached because 0 is even, so 0 gets caught in the first branch if n%2 == 0:
You can fix it by changing the order of the branches:
def odeven(n):
if (n == 0):
return 0
elif n%2 == 0:
print("even no. : ",n)
else: # n%2 != 0
print("odd no. : ",n)
return odeven(n-1)
result = odeven(10)
print("result odd ={}".format(result))
Output:
even no. : 10
odd no. : 9
even no. : 8
odd no. : 7
even no. : 6
odd no. : 5
even no. : 4
odd no. : 3
even no. : 2
odd no. : 1
result odd =0
Further improvements
You can figure out whether a number n is odd or even simply by checking the value of n % 2. There is no need for recursion here.
Presumably this is an exercise that was given by a teacher who wants you to use recursion to figure out whether n is odd or even without using %. This is terribly inefficient and has no use in practice, and is purely an exercise to learn about recursion. In that case, do not use %. Operator % solves the whole problem by itself so if you use it, you don't need to use recursion. It defeats the purpose of the exercise.
Compare the two following functions:
def oddeven_direct(n):
if (n % 2 == 0):
return 'even'
else:
return 'odd'
def oddeven_recursive(n):
if (n == 0):
return 'even'
elif (n == 1):
return 'odd'
elif (n > 1):
return oddeven_recursive(n-2)
elif (n < 0):
return oddeven_recursive(-n)
print(oddeven_direct(10))
print(oddeven_recursive(10))
Note that I did not call function print inside the function. The function returns a result, which is 'even' or 'odd', and doesn't print anything. This is more consistent. If the user calling the function wants to print something, they can call print themselves.
A variation
Notice how the recursive call jumped from n to n-2? This is because I know that n and n-2 will have the same parity (both odd or both even); and we have two base cases, 0 and 1, to which we're guaranteed to arrive when jumping 2 by 2.
If we had jumped from n to n-1 instead, we'd have run into an issue because n and n-1 have different parity (odd and even or even and odd), so we need some way to keep track of this change of parity during the recursion.
This can be achieved by implementing two distinct functions, is_odd and is_even, and using the recursion to express the facts "n is odd if n-1 is even" and "n is even if n-1 is odd".
Since those functions have names that sound like yes/no question, or true/false question, we will make them return True or False, which are called boolean values.
def is_odd(n):
if n == 0:
return False
else:
return is_even(n-1)
def is_even(n):
if n == 0:
return True
else:
return is_odd(n-1)
print('10 is even? {}'.format(is_even(10)))
print('10 is odd? {}'.format(is_odd(10)))
Note that python knows boolean values very well and we can make the code shorter using the two lazy logic operators and and or:
def is_odd(n):
return n != 0 and is_even(n-1)
def is_even(n):
return n == 0 or is_odd(n-1)
print('10 is even? {}'.format(is_even(10)))
print('10 is odd? {}'.format(is_odd(10)))
You get an error, because you call the function inside the function and never stop that function call so it recurses over and over again. Python allows recursion but only until a defined end is reached
To change this limit:
https://www.geeksforgeeks.org/python-handling-recursion-limit/
Also your recursion gets into minus, because you call your function attribute (= (n)) allways one number lower than the function call before:
Your function is now called with
odeven(9)
and so on until it reaches -985, which is in your case the maximum recursion depth which results in:
[Previous line repeated 992 more times]
File "/python/test.py", line 5, in odeven
print("odd no. : ",n)
I have some code which gives me the answer I want, but I'm having trouble stopping it once I get the
answer I want.
Here's my code:
multiples = range(1,10)
n = 1
while n>0:
for i in multiples:
if n%i!=0:
n = n + 1
continue
elif n%10==0:
print(n)
This is an attempt at solving problem 5 of Project Euler. Essentially, I'm supposed to get the smallest multiple of all the digits within a given range.
Now, when i run the above code using the example given (1-10 should yield 2520 as the smallest multiple), i get the answer right. However, the code continues to run infinitely and print the answer without breaking. Also, the moment I add the break statement to the end like so:
multiples = range(1,10)
n = 1
while n>0:
for i in multiples:
if n%i!=0:
n = n + 1
continue
elif n%10==0:
print(n)
break
The code just keeps spamming the number 30. Any ideas why this is happening. For the record, I'm not really looking for an alternative solution to this question (the goal is to learn after all), but those are welcome. What I want to know most of all is where I went wrong.
You never break out of your while loop. The for is the entire while body. break interrupts only the innermost loop; you have no mechanism to leave the while loop. Note that your continue doesn't do anything; it applies to the for loop, which is about to continue, anyway, since that's the last statement in the loop (in that control flow).
I can't really suggest a repair for this, since it's not clear how you expect this to solve the stated problem. In general, though, I think that you're a little confused: you use one loop to control n and the other to step through divisors, but you haven't properly tracked your algorithm to your code.
One way to deal with this is to have an exception. At best a custom one.
multiples = range(1,10)
n = 1
class MyBreak(Exception):
pass
while n>0:
try:
for i in multiples:
if n%i!=0:
n = n + 1
continue
elif n%10==0:
print(n)
raise MyBreak()
except MyBreak:
# now you are free :)
break
With this brake you stop only for loop, to exit whole cycle you should create trigger variable, for example:
multiples = range(1,10)
n = 1
tg = 0
while n>0:
for i in multiples:
if n%i!=0:
n = n + 1
continue
elif n%10==0:
print(n)
tg = 1
break
if tg != 0:
break
Or it'll be better to use a function and stop a cycle by return:
def func():
multiples = range(1,10)
n = 1
while n>0:
for i in multiples:
if n%i!=0:
n = n + 1
continue
elif n%10==0:
print(n)
return n
Given an integer, , perform the following conditional actions:
If is odd, print Weird
If is even and in the inclusive range of 2 to 5, print Not Weird
If is even and in the inclusive range of 6 to 20, print Weird
If is even and greater than 20, print Not Weird
Every time I run the code, it only executes the else statement else: print("lol") , whether I type any value from 1 to 25.
What's wrong?
n = input("Enter a number here: ")
num = int(n)
if (num % 2) == 0 >= 2 and (num % 2) == 0 <= 5:
print("Not Weird")
elif num % 2 == 0 >= 6 and num % 2 == 0 <= 20:
print("Weird")
elif num % 2 == 0 > 20:
print("Not Weird")
else:
print("lol")
(num % 2) == 0 >= 2 is not the correct way to check if a number is even and in the range you want. If you want to check if num is even and in that range, you'd do something like:
(((num % 2) == 0) and (1 < num <= 5))
As others have pointed out your conditions are not written correctly. Here's the first part to get you started (if the number is odd, and if the number is even and between 2 and 5):
n = input("Enter a number here: ")
num = int(n)
isEven = (num % 2) == 0
if not isEven:
print("Weird")
elif 2 <= num <= 5:
print("Not Weird")
Just as Random Davis said , the problem is in precedence(or whatever it is called sorry XD) so what it does is :
when you check for [(num % 2) == 0 >= 2] : what it does is first checks if num is even[(num % 2)] and then it checks the relation between 0 and 2[0 >= 2] and then equates [ [(num % 2){maybe true or false} == (0 >= 2){always false}]] which results in a LOGICAL ERROR
Rather what you should do is this
(((num % 2) == 0) and (1 < num <= 5)) {just as Random Davis said.}
what it does is checks whether number is even or not[(num % 2) == 0)] and then if number is between 1 and 5[(1 < num <= 5)] and then cheks if both are true or not.
Hope you understand what I am trying to say.
There are a couple of problems with your solution. There is nothing wrong with your if-else statements. They are valid, but are not doing what you want. Looking at the first if:
if (num % 2) == 0 >= 2 and (num % 2) == 0 <= 5:
print("Not Weird")
You first use modulo and test for equality with 0, which is a reasonable test for even vs odd. However, you then compare the boolean result of the even-add test with the number 2. You want to test num with 2, not the boolean of evenness with 2. Testing a boolean result for >= 2 always comes out false. That is True >= 2 is False; and False >=2 is False. Python is smart enough to know that False and (anything else) will be false, so Python won't even evaluate the rest of the statement.
So to test if a number is even and in the range of 2 to 5 inclusive you should want to do:
if num % 2 == 0 and 2 <= num <= 5 :
print("Not Weird")
A few words about Python: Python differs from other languages in that the form "2 <= num <= 5" is a legal construct. It is darn convenient, but atypical among languages. In other languages the initial 2<=num results in a boolean and then then you would get an error comparing a boolean to 5. It is interesting that Python does not throw an error but results in a boolean. Though Python is atypical it is useful. Other languages would require something like
if (2 <= num) and (num <= 5) then # Not a Python statement!
Another oddity is that the and operator is lower precedence than the other comparison operators. In other languages and is higher or equal. The Python rules of precedence let you use "num % 2 == 0 and 2 <= num <= 5", so the evenness test and the double inequality run before the "and", so you get a natureal human result. BUT IT IS DIFFERENT FROM OTHER LANGUAGES. You will probably learn a lot of languages over the years. Appreciate how they work.
I'll let you figure out the rest of the statements in your original solution. However, there is another problem: You don't handle odd numbers in your solution correctly, since you are printing out lol. For debugging you are doing the correct thing, since the printing of "Weird" for odd numbers is an ambiguous result. If you did that on purpose for debugging, CONGRATULATIONS!, you are thinking like a programmer digging through your program.
I submit that your approach is a bit of a brute force approach. The directions do say:
If is odd, print Weird
If is even and in the inclusive range of 2 to 5, print Not Weird
If is even and in the inclusive range of 6 to 20, print Weird
If is even and greater than 20, print Not Weird
As a programmer, you do not have to follow the given directions. You need to formulate a solution that results in an algorithm that meets the specifications. Part of the art of programming is to recognize whether the specs are subject to change, anticipate needs for updates, and even correct some assumptions that the specs make that might be in error. So while this is a simple task, it is rich in teaching. (Kudo's to your instructor).
One way to look at the specs is that it implies non-negative inputs. What is one to do with -4 or 0? Not in the specs. It is fair to look at proposed input and see what it is so you can handle that case. Sometimes other logic is added to reject illegal entries. It isn't specified here, so I would handle it with a comment in the code that input is expected to be a positive non-zero integer.
In addition, there is a certain approach that is a bit more wholistic: If odd print Weird and quit, otherwise you know num is even, so further checking is not needed for evenness. So then you print Weird for num in the range [6..20], otherwise print Not Weird. The big picture is odds print Weird, any number [6..20] prints Weird, everything else prints Not Weird.
if num % 2 == 1 : # Handle odd num
print("Weird") # Any odd prints Weird
else: # Handle even num
if 6 <= num <= 20:
print("Weird")
else:
print("Not Weird")
The point is once you do a test you know womething that can be carried forward in your code. Once you test that something is odd, handle it, and after that the code knows the number if not odd is even, and you don't have to keep testing it. Logically, if odd print and be done. Otherwise (num is even) print "Weird" for num in [6..20], print "Not Weird" otherwise. Rather than 3 tests when a number is even now there is just the one test for num being in the range [6..20].
A few comments are sprinkled in. No testing for input less than 1.
The whole thing could be simplified further
if num % 2 == 1 or 6 <= num <= 20: print("Weird")
else:print("Not Weird")
That does simplify the whole thing.
It is interesting that in programming the simple question of "what is wrong with my statement" can sometimes be addressed with "should I be using this approach?" I've gone far afield with this answer. Originally, what's with my if statement was the issue, but this little gem of a problem is really teaching a lot. (Again, Kudo's to the teacher!)
So, do you transform thw whole question and use an or, or does the first approach work better. In the real world you might have a sense of how the specification may be changed and your solution will be best when it is correct, uses reasonable resources, and is maintainable.
I need to create a program that takes in an array of numbers, check if each number is greater than the sum of all previous numbers, and output true if the condition is met, and false, if not. My trial is presented below:
import fileinput
a0 = [int(i) for i in fileinput.input()]
a = a0[1:]
b=[]
for i in range(1, a0[0]+1):
b.append(a[i])
if (a[i+1] > sum(b)):
print("true")
break
else:
print ("false")
break
My program works for half of the test cases but fails for the other test. Could you please help me figure out what i am doing wrongly. Many thanks for your assistance.
You are breaking too early in the true case. Only because the first element checks, doesn't mean all others will, too:
for i in range(1, a0[0]+1):
b.append(a[i])
if (a[i+1] <= sum(b)):
print ("false")
break
else: # for-else: else is executed only if loop isn't `break`ed out of
print("true")
Only once the loop has finished without finding a counter example, you can be sure that it holds for the entire list.
A more concise of writing this, would be:
import fileinput
_, *a = (int(i) for i in fileinput.input())
s = 0 # just keep track of total
for num in a:
if (num <= s):
print("false")
break
s += num
else:
print("true")
My goal is to make a program that prints onscreen all of the prime numbers it can find, however I have this issue where the while loop runs only once, instead of repeating forever.
def isPrime(num):
if num < 2:
return False
if num == 2:
return True
if num % 2 == 0:
return False
i = 3
while i * i <= num:
if num % i == 0:
return False
i += 2
x = 1
while True:
x += 1
if isPrime(x):
print (x)
I also have tried adding print("You can see this.") at the very end of the code, and it runs, but only once.
I'm sure it's a common mistake, since Python is very strict on indentation, but could you guys help me discover it? Thanks in advance.
You need to return True at the very end, after and outside the final loop. Otherwise the function ends without explicitly returning anything, so it implicitly returns None which is interpreted as false.
The i +=2 is indented too deep, the inner loop never quits.
It should read
while i * i <= num:
if num % i == 0:
return False
i += 2
Otherwise i never increases and the loop goes on and on and on.