Im working on a finger exercise from Guttag Intro to computer science and programming using python, and Im working on the following finger exercise:
Finger Exercise: Implement a function that satisfies the specification
def findAnEven(l):
"""Assumes l is a list of integers
Returns the first even number in l
Raises ValueError if l does not contain an even number"""
This is what I wrote so far, it get's the job done, but is definitely not what Guttag intended as an answer.
def isEven(l):
"""Assumes l is a list of integars
returns the first even number in list
raises an exception if no even number in list"""
for i in l:
if i % 2 == 0:
print i, " is the first even number in the list"
exit()
raise ValueError("No even numbers in list!")
I would highly appreciate any input on how professor Guttag intended the code to look. I'm assuming I should have used the try statement somewhere, and the using the exit statement is very crude in this context. Thanks in advance.
The issue with your code is the usage of exit(). Generally return will exit for you. To fix the code, just remove it:
def isEven(l):
for i in l:
if i % 2 == 0:
return i
raise ValueError("No even numbers in list!")
I'm answering this by using the try-except:
def findEven(L):
try:
for num in L:
if num%2==0:
return num
else:
num/0
except:
raise ValueError
To enter the except block, there needs to be an error in the try block. I intently added a Zero division operation in the try block to get it to produce the ZeroDivisionError in case no even number was found. This error allows the exception block to execute. Hope it helps someone else in the same situation.
I am also working on this part. This is my code:
def findEven(L):
try:
for num in L:
if num%2==0:
return num
else:
num/0
except ZeroDivisionError:
print("No even numbers in list!")
except:
raise ValueError("findEven called with bad arguments")
I found that if I didn't use ZeroDivisionError,the IDLE Shell will show ZeroDivisionError first, and then show this line
During handling of the above exception, another exception occurred:
Related
I get what it does but I don't understand why we do it? Why are we trying to except something?
For example:
for i, value in enumerate(arr):
try:
result_dict[value] += 1
except KeyError:
result_dict[value] = 1
Why do I have to do except KeyError? I don't know why a KeyError is thrown. Why can't I just do
result_dict[value] += 1
in the first place?
What goes inside the except block for any try/catch? I get the error has to be thrown but what condition has to do inside the except block?
Sorry if my question is too dumb. I'm a beginner.
TLDR
try/except blocks makes sure that your program continues running rather than ending abruptly. By including a except KeyError, we are specifically making sure that the program does not end abruptly if a KeyError occurs. result_dict[value] += 1 will throw an error if value is not a key in the dictionary, because it tries to do access a key that does not exist. The += makes the code run similarly to:
result_dict[value] = result_dict[value] + 1
and since value is not in result_dict, it is similar to saying
result_dict[value] = None + 1
which is bad.
The Non-TLDR version
When an error occurs in python, the program usually terminates abruptly and exits. It does not run any code that occurs below the part where the exception occurs. For example, take the following code. It takes 2 numbers from the user a and b, and it will output a/b
a = int(input("Enter a value for a: "))
b = int(input("Enter a value for b: "))
print("a/b is:", a/b)
If the user gives a valid input (say a=4, b=2) the program proceeds smoothly. However if the user were to give, say a = "c", then the following happens
Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'c'
And the program ends abruptly. It is perfectly valid to have the program end like that, but rarely do you want the program to end abruptly. Take the case where the user has 1000 inputs, and the last one messes up. The user will then have to restart the program and re-input all 1000 inputs again, because the program ended abruptly.
So now we introduce a try/except block. We know that converting a non-numeric character into an integer will throw a ValueError as seen in the error, so we will handle them accordingly
while True:
try:
a = int(input("Enter a value for a: "))
break
except:
print("An error has occurred. Please input a again")
while True:
try:
b = int(input("Enter a value for b: "))
break
except:
print("An error has occurred. Please input b again")
print("a/b is:", a/b)
So now, we take an input from the user, try to convert it into an integer and put that value into a. If it succeeds, it will proceed smoothly to the next line (break) and exit the loop. If it fails, then an exception will occur, and it will enter the except block, where it will print a helpful error message, and run the loop again (until the user enters a valid input). Now the program doesn't just terminate abruptly when it fails. It gives appropriate feedback to the user, and lets the user retry the input again.
That is a general exception block, where you just catch any exception.
But let's now say that there are multiple possible errors that could occur. Take the following code:
a = input()
b = input()
print(int(a)/int(b))
print("I am done")
Now a few errors can occur. One of them is the ValueError stated above, where the input given cannot be converted into an integer. The other error, is a ZeroDivisionError where b=0. Python doesn't like dividing by zero, hence it will throw an exception and terminate the program immediately.
So now, you want to print a special message for each type of program. How you do that is by catching specific exceptions
a = input("Enter a value for a: ")
b = input("Enter a value for b: ")
try:
print(int(a)/int(b))
except ValueError:
print("We cannot convert a non-numeric character to an integer")
except ZeroDivisionError:
print("We cannot divide by 0")
except:
print("Some unexpected error has occurred")
print("I am done")
If python was unable to convert the input into an integer, it will enter the ValueError block of the code, and print "We cannot convert a non-numeric character to an integer"
If python tried to divide by 0, then it will enter the ZeroDivisionError block and print "We cannot divide by 0"
If any other type of error occurred, it will end up in the final except block and print "Some unexpected error has occurred"
And after the exception is handled, it prints "I am done"
Note that if the final except block was not there to catch any other exceptions, then the program will not terminate nicely because the exception was unhandled, and it will not print the final statement.
Now, how does one realise what possible error can occur? That is up to practice, and once you get familiar with the errors, you can handle them accordingly. Or, purposefully make your program throw exceptions, and read the stack trace for what kind of exceptions occur. And then handle them accordingly. You don't have to handle each specific error differently, you could handle all of them in the same way.
You can read more here: Python's documentation for errors and exceptions
Here's why. You cant add to something that is None. For example say var1 = None. I couldn't do something like var = var + 1. That would throw an error. In the example you shared the code will check if you can add 1 to value's key. If you cannot do this you assign a value to the key.
for i, value in enumerate(arr):
try:
#Try and add 1 to a dict key's value.
result_dict[value] += 1
except KeyError:
#Say we get an error we need to assign the dict key's value to 1.
result_dict[value] = 1
A KeyError will crash/terminate your program if result_dict[value] doesn't exist. By using an except block, you tell the program what to do in the event of a KeyError (here, assign result_dict[value] = 1 if it doesn't exist), and then the program continues. Basically, you're avoiding a crash.
Let's say your value is "banana". If you don't have a result_dict["banana"], you can't add 1 to nothing, i.e. None += 1.
By using except KeyError, you intercept the error before it stops your program, and now you have set a key-value pair for your result_dict, rather than terminating the program.
Let's start with an example
We have tenants in an apartment building who can reserve parking spots. Some tenants have no car and won't have a parking spot, but only tenants can reserve a spot. We track parking spots in a dictionary:
parking_spots = { "alice": 1, "bob": 2, "chris": 0 }
Chris doesn't have spots because he walks to work.
What should happen if Eve tries to reserve a spot?
parking_spots["eve"]
That code asks "how many spots has eve reserved?" However, another question this answers is whether Eve is a tenant of the building at all. Python represents this by having parking_spots["eve"] throw a KeyError which is not like any other value. If python didn't do this and returned 0 by default, then parking_spots["eve"] and parking_spots["chris"] would look the same.
But wait, I know that this particular dictionary isn't being used that way
Cool, that's pretty common. It's so common in fact that there are multiple ways of doing this.
Instead of
result_dict = {}
for i, value in enumerate(arr):
try:
result_dict[value] += 1
except KeyError:
result_dict[value] = 1
You can use
result_dict = {}
result_dict.setdefault(0)
result_dict += 1
Or you can use defaultdict.
from collections import defaultdict
result_dict = defaultdict(int)
result_dict += 1
Some CS Theory
There are two theoretical concepts that we could talk about here:
Exceptions as a control flow mechanism
The api of a dictionary
Exceptions for Control Flow
try/catch is style of control flow. It is simply a nicer way to think of code for certain cases. It is almost never required as long as you can use if/else, but is many times the best way to think about code.
Depending on who you talk to, exception handling can be a somewhat controversial feature:
C++ - Arguments for Exceptions over Return Codes
In my opinion, it's rare that exceptions are truly the right answer if you design a system from scratch. Generally, I prefer using an Option (or more generally sum types).
However, in many cases, they are the best answer given you starting constraints.
Dictionary API
Python throwing an exception when the key isn't present is a design choice and not the only way the API could be written. Instead, it could simply return None. Many languages follow the latter approach as they consider it more safe - especially when you work in a modern typed language like Rust, Haskell, Elm, etc.
Further Reading
I would also encourage you to read Amp's answer as it covers some other details on the particulars of exception handling that may be instructive.
I am doing a python course where they suggested a try and except block in a while loop in order to keep asking for input until the condition is satisfied. Intuitively I feel it is shorter to just call the function again in the "except" block like this:
def exceptiontest():
try:
print(int(input("number 1: "))+int(input("number 2:")))
except:
print("a mistake happened")
exceptiontest()
exceptiontest()
When asking on the forum on the course I got the reply that it is not the same. I am a bit confused now. Anyone that can clarify for me? Thanks in advance!
Calling the function in the except will eventually raise a RecursionError: maximum recursion depth exceeded error if you keep entering bad inputs. Generally must humans won't be entering that many bad data to hit the error before they give up, but you are unnecessarily putting function calls on a stack.
A while loop is better since it's one function call, waiting for a valid input. IT doesn't waste any more resources than it needs.
while loop, for two reasons
it's clearer to read: while not success, try again
recursion is not free. It leaves the previous function stack open. it could run out of memory (probably won't, in this case, but in principle, avoid it)
Another reason to use the while loop which has not yet been mentioned is that you could leverage the assignment expressions coming with Python 3.8.
The function add encapsulates getting two numbers and trying to add them.
def add():
'try to add two numbers from user input, return None on failure'
x = input('number 1: ')
y = input('number 2: ')
try:
return float(x) + float(y)
except TypeError, ValueError:
return None
The following while loop runs as long as there is no result.
while (result := add()) is None:
print('you made a mistake, make sure to input two numbers!')
# use result
I'm working on a school project and it specifically asks for a while not end-of-file loop which I don't know how to do in Python. I'm taking in user input (not from an external file) and computing some math in this infinite loop until they CTRL+C to break the loop. Any thoughts would really help me out. I've added part of the instruction if that helps clarify. Thanks.
Your loop is supposed to stop on two conditions:
An illegal value was entered, ie some value that couldn't be converted to a float. In this case, a ValueError will be raised.
You entered ctrl-Z, which means an EOF. (Sorry, having no Windows here, I just tested it on Linux, where I think that ctrl-D is the equivalent of the Windows ctrl-Z). An EOFError will be raised.
So, you should just create an infinite loop, and break out of it when one of these exceptions occur.
I separated the handling of the exceptions so that you can see what happens and print some meaningful error message:
while True:
try:
amount = float(input())
print(amount) # do your stuff here
except ValueError as err:
print('Terminating because', err)
break
except EOFError:
print('EOF!')
break
If you just want to quit without doing anything more, you can handle both exceptions the same way:
while True:
try:
amount = float(input())
print(amount) # do your stuff here
except (ValueError, EOFError):
break
Use the following:-
while True:
amount = raw_input("Dollar Amount: ")
try:
amount = float(amount)
# do your calculation with amount
# as per your needs here
except ValueError:
print 'Cannot parse'
break
I am making a calculator (using tkinter) and I need to have a limit so if the user enters an input of more than 999, an error message appears and the numbers are not calculated (it is a school project). When I run the script from below, at school it just appears with a blank GUI and on my home computer it says 'unindent does not match any outer indentation level'. How can I solve this?
Thanks
P.S. I am using Python 3.3.2
def calc(self):
try:
self.display.set(self.validate_result(eval(self.display.get())))
self.need_clr = True
except:
showerror('Operation Error', 'Illegal Operation')
self.display.set('')
self.need_clr = False
def validate_result(self, result):
if result >= 1000:
raise ValueError('result too big!')
else:
return result
Python uses indentation to distinguish levels of scope.
Here all your code seems to be entirely indented, so Python thinks all your code is in an inner scope, and tries to find the outer scope that contains it, but there isn't any.
You should try with this indentation :
def calc(self):
try:
...
def calc(self):
try:
...
Edit : also, you seem to have other indentation problems in the second function. You must align except with try, and there is one space missing before if result >= 1000:.
According to the Python documentation on idioms and anti-idioms in relation to exceptions: "You should try to use as few except clauses in your code as you can — the ones you do use will usually be inside calls which should always succeed, or a catch-all in a main function." Taking this sentence in sections...
"You should try to use as few except clauses in your code as you can"
A bit confusing for a newbie like myself, I thought it was good practise in Python to use the EAFP style -i.e. many try and except statements. Or am I missing the point?
"the ones you do use will usually be inside calls which should always succeed"
I don't understand the point that's being made here.
"or a catch-all in a main function."
So it's good style to any let code that throws an exception to simply pass it up the call stack until it reaches the top level where you have really generic exception handling?
"You should try to use as few except clauses in your code as you can"
It's easy to litter your code with exceptions:
def solve_linear(mat1, mat2):
det1 = determinant(mat1)
det2 = determinant(mat2)
try:
return det1 / det2
except ZeroDivisionError:
raise NoSolution
Here, it's probably fine to let the ZeroDivisionError propagate. You don't need to catch it.
"the ones you do use will usually be inside calls which should always succeed"
For example, look at this code which reads a file, or returns a cached value. It normally succeeds, in spite of the KeyError exception:
def read_file(path):
try:
return cache[path]
except KeyError:
fp = open(path, 'rb')
data = fp.read()
fp.close()
cache[path] = data
return data
"or a catch-all in a main function."
If your program is interactive, you'll probably want to catch almost everything at the top level. Here's the top loop of an interactive command-line program:
def main():
while True:
try:
text = raw_input('enter command: ')
cmd = parse_command(text)
except EOFError:
return
except KeyboardInterrupt:
return
except ValueError:
print 'Syntax error'
continue
try:
run_cmd(cmd)
except SystemExit:
raise
except Exception:
traceback.print_exc()
Concerning the first point, the whole point of using exceptions is that you don't have to wrap every line in one! E.g. in C, errors are usually determined by the return value of a function call. So you have to check those after every call if you want to catch all errors. With Python you can group a (possibly large) block of statements that go together in a try/except block and only deal with all errors once.
The second point is that (if possible) you want to solve failures close to the point where they occur. E.g. you are reading data from a network and get zero bytes. In that case it is usually perfectly allright to wait and try again.
The last point is that sometimes an error is so big that it cannot be handled at a low level. E.g. if you are trying to open a file that not exist, it wil fail. And your program cannot do whatever it was going to do with the contents of the file. It is best to handle that at the top level of the program and ask the user for another file name or maybe quit the program.
I think the point is that exceptions should be used only for 'exceptional' circumstances. That is the meaning behind the use "in calls which will usually succeed". An example of this might be some computation that under some really weird circumstances ends having to do a division by zero. Then you can enclose that in a try / except statement to deal with that possibility.
The catch-all in a main function would be applicable to the same scenario. Say your calculations end up with a division by zero somewhere deep in the call stack. From this point you can't continue, so there's no point in having a try/except statement right at the point of failure. It would make more sense to just have one at a higher level where you can reasonably recover from the error.
The example they give in the documentation is an example of this. When calling 'get_status' you would expect the file to be there. If it doesn't then you have the except statement to deal with that (although, as mentioned, in that particular case the 'with' statement is much better).
The Python philosophy is typically to "ask forgiveness, not permission." But the idea isn't to use a try-except clause to catch ALL possible errors. Ideally, each try-except will only catch the error(s) that are relevant.
BAD (doesn't specify a specific exception type):
a = [1, 2, 3]
i = 3
try:
print a[i]
except:
print "Not found!"
GOOD (only handles the exception we expect to get):
a = [1, 2, 3]
i = 3
try:
print a[i]
except IndexError:
print "Not found!"
The reason this is important is so we don't obscure other possible code errors. What if, in this example, i was 1.8? The first example would print Not Found!, obscuring the real issue, but the second example would return TypeError: list indices must be integers, not float letting us know that there's a logical flaw in our code.