I have some code below that is meant to check if a list of lists contains an empty string. In context, the user of my application will fill out survey questions, but if they leave one of the survey questions empty, then I want to alert them that they need to go back and fill out the survey. I need to perform this check in a bunch of different places, so I thought that a class would be a good use-case to improve the readability and portability of my program.
However, I have come to learn of try-except blocks and thought maybe it would be a better place for the essence of my code. But I am having some issues converting my simple class into a try-except block, and would like to try and implement it this way if I can. However, I think what I want to do might not be appropriate for a try-test block, so I was hoping to get some feedback.
class ErrorCheck():
def __init__(self, survey_responses):
self.survey_responses = survey_responses
def check_empty(self):
for item in self.survey_responses:
if '' in item:
print('One of these is empty')
x = ErrorCheck([['abc'],[2],['apples'],['']])
x.check_empty()
The code that you're trying to implement is pretty much correct. Except for the fact that if you want to highlight an error, instead of just using a print function, use raise Exception() and in the parentheses insert a string, in your case 'One of these is empty'.
This will result in output like this:
Exception: One of these is empty
which is probably what you're looking for.
As others already pointed out, what you want do is probably raise an exception, after you raise it you can catch it in a try...except block and do something about it:
survey_responses = ['a','','c']
def check_empty(responses):
for response in responses:
if response == '':
raise Exception('Missing Answer: One or more answers are empty')
try:
check_empty(survey_responses)
except Exception as exc:
print(exc)
Related
I currently have the function below which has an if-else statement within it. After reading this post I thought it may be better to use try-catch Exception Handling instead. However, I am not sure how to do this. Basically, if the currency inputted is not AUD I want to throw an Exception with the print statement below.
def update(self, currency):
if self.currency == 'AUD':
url = 'http://www.rba.gov.au/statistics/tables/csv/f17-yields.csv'
response = urllib2.urlopen(url)
text = response.read()
csvfile = StringIO.StringIO(text)
df = pd.read_csv(csvfile)
print df
else:
print('This currency is not available in Database')
You generally don't want to be raising and catching an exception at the same place. Instead, you want to raise the exception where the error is first noticed, and catch it wherever it makes sense to report the issue.
In the code you've shown, you just want to replace the print call with a raise statement, probably of a ValueError. Pass the text you're printing as an argument to the exception:
raise ValueError('This currency is not available in Database')
Since you haven't shown where update is called, I don't know for sure where it would be appropriate to catch the exception. One reason that exceptions are useful (rather than if/else tests) is that you can let the exception bubble out of several functions or structural blocks if there's no useful way to handle them at that level.
Using exception handling instead of an if-else statement will be much slower.
I've benchmarked a similar comparison for locating a list of keys in a dictionary here, and timings are attached. For me, it was 5 times slower.
If you want to force exception handling, you can use assert:
def update(self, currency):
try:
assert self.currency == 'AUD'
url = 'http://www.rba.gov.au/statistics/tables/csv/f17-yields.csv'
response = urllib2.urlopen(url)
text = response.read()
csvfile = StringIO.StringIO(text)
df = pd.read_csv(csvfile)
print df
except AssertionError:
print('This currency is not available in Database')
Not necessarily ideal in this case (this is a LBYL scenario, in my opinion), since the equality test should be faster, more readable, and scale better to more currencies, assuming you start off with a wide variety of different currencies.
If I have such code in the end of function:
try:
return map(float, result)
except ValueError, e:
print "error", e
Is it correct to use try / except in return part of method?
Is there a wiser way to solve this?
Keep it simple: no try block
It took me a while to learn, that in Python it is natural, that functions throw exceptions up. I have spent too much effort on handling these problems in the place the problem occurred.
The code can become much simpler and also easier to maintain if you simply let the exception bubble up. This allows for detecting problems on the level, where it is appropriate.
One option is:
try:
return map(float, result)
except ValueError, e:
print "error", e
raise
but this introduces print from within some deep function. The same can be provided by raise which let upper level code to do what is appropriate.
With this context, my preferred solution looks:
return map(float, result)
No need to dance around, do, what is expected to be done, and throw an exception up, if there is a problem.
If you surround the code block containing a return statement with an try/except clause, you should definitely spend some thoughts of what should be returned, if an exception actually occurs:
In you example, the function will simply return None. If it's that what you want, I would suggest to explicitely add a return None like
except ValueError, e:
print "error", e
return None
in your except block to make that fact clear.
Other possibilities would be to return a "default value" (empty map in this case) or to "reraise" the exception using
except ValueError, e:
print "error", e
raise
It depends on how the function is used, under what circumstances you expect exceptions and on your general design which option you want to choose.
As is often the case in languages with exceptions, programmers assume that printing an error message "handles" it.
Printing an error message doesn't handle anything; you might as well have put pass there instead. This causes problems because the the code was expecting the try block to accomplish something and that something has not happened.
In Python, you should:
figure out where the error can actually be handled in the sense that the fault is actually rectified, or
let the exception unwind to the top and abort the program
Having a program abort with an exception is infinitely better than having it run and yield inaccurate results.
So unless you know that your code can accept an empty list, you shouldn't return anything that you thought deserved a try block.
Here is the normal way of catching and throwing exceptions to callee's
def check(a):
data = {}
if not a:
raise Exception("'a' was bad")
return data
def doSomething():
try:
data = check(None)
except Exception, e:
print e
Here is an alternative + a few things I like:
'data' is always present, the 'check' function could set up some
defaults for data, the logic is then contained within the function
and doesn't have to be repeated. Also means that a dev can't make the mistake of trying to access data when an exception has occurred. (data could be defined at the very top of 'doSomething' function + assigned some defaults)
You don't have to have try/excepts everywhere cluttering up the 'doSomething' functions
def check(a):
errors = []
data = {}
if not a:
errors.append("'a' was bad")
return data, errors
def doSomething():
data, errors = check(None)
if errors:
print errors
Is there anything wrong with it? what are people's opinions?
There are times when the second approach can be useful (for instance, if you're doing a sequence of relatively independent operations and just want to keep a record of which ones failed). But if your goal is to prevent continuing in an incorrect state (i.e., not "make the mistake of trying to access data when an exception has occurred"), the second way is not good. If you need to do the check at all, you probably want to do it like this:
def check(a):
data = {}
if not a:
raise Exception("'a' was bad")
return data
def doSomething():
data = check(None)
# continue using data
That is, do the check and, if it succeeds, just keep going. You don't need to "clutter up" the code with except. You should only use try/except if you can actually handle the error in some way. If you can't, then you want the exception to continue to propagate, and if necessary, propagate all the way up and stop the program, because that will stop you from going on to use data in an invalid way.
Moreover, if it's possible to continue after the check but still "make the mistake" of accessing invalid data, then you didn't do a very good check. The point of the check, if there is one, should be to ensure that you can confidently proceed as long as the check doesn't raise an exception. The way you're doing it, you basically do the check twice: you run check, and then you check for an exception. Instead, just run the check. If it fails, raise an exception. If it succeeds, go on with your code. If you want the check to distinguish recoverable and unrecoverable errors and log the unrecoverable ones, then just do the logging in the check.
Of course, in many cases you can make it even simpler:
def doSomething():
data.blah()
# use data however you're going to use it
In other words, just do what you're going to do. You will then get an exception if you do something with data that doesn't work. There's often no reason to put in a separate explicit check. (There are certainly valid reasons for checks, of course. One would be if the actual operation is expensive and might fail at a late stage, so you want to check for validity upfront to avoid wasting time on an operation that will fail after a long computation. Another reason might be if the operation involves I/O or concurrency of some kind and could leave some shared resource in an invalid state.)
Some years from now, when you read your own code again and try to figure out what on earth you were trying to do, you'll be glad for all the clutter of the try-excepts that help make perfectly obvious what is an error and what is data.
try/excepts are not clutter; They increase the code readability by indicating that this piece of code can "expect" an exception. If you mix your logic-"ifs" with error-handling "ifs" - you may lose some readability in your code.
Further, if you know 'a' being None is the only kind of error you will have, you can write an if and handle it this way; Makes sense in this simple example you gave.
However, if a different error happens, an exception is raised anyway!
I wouldn't recommend to use it as a general programming practice to avoid try/except anywhere. It is acknowledging and marking places in code where exceptions happen.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Does a exception with just a raise have any use?
Is there any value to re-raising an exception with no other code in between?
try:
#code
except Exception:
raise
I was recently looking through some code and saw a few blocks like these with nothing extra in the except block but another raise. I assume this was a mistake and poor decision making, am I right?
I've seen similar code before in a (set of) horrible VB.NET projects. Either the intent was to catch and log exceptions, without ever coming back to finish the logging, or they heard "you must catch exceptions", implemented this functionality, and someone else decided it should just re-raise.
There is no benefit to the above code.
I am not able to come up with something useful, other than to keep it as a placeholder for later insertion to catch useful exceptions.
It kind of avoids re-indenting the code, when you want to include the "try .. except.." blocks later on.
Example built on this question. If there's some other except's in the try block, it can be used to filter the exceptions, but alone it's pointless.
class FruitException(Exception): pass
try:
raise FruitException
except FruitException:
print "we got a bad fruit"
raise
except Exception:
print "not fruit related, irrelevant."
Yes, this is usually a bad practice. The only (somewhat) correct usage I've seen of this pattern was before VB.NET had a Using construct available. Usage looked something like:
Dim myResource As DisposableService
Try
myResource = New DisposableService()
' This might throw an exception....
myResource.DoSomething()
Catch
Throw
Finally
' Perform cleanup on resource
If Not myResource Is Nothing Then
myResource.Dispose()
End If
End Try
Other than that, I really can't think of a good use case for this sort of thing.
sometimes it useful let me give you a real example that i did i my work :
this was is in a decorator that wrap func : so basically what i have wanted is to re-raise the error that i catched when i called the function func so that the decorator don't change the behavior of the function func, because when func raise an exception the exception are send to the GUI so that an error message can pop up to the user,
and for the try except i use it because i want to execute the code in finally even if an exception is raised
try:
result = func(self, *args, **kws)
return result
except Exception, ex:
# If an exception is raised save it also.
logging_data['message'] = str(ex)
logging_data['type'] = 'exception'
# Raise the error catched here so that we could have
# the same behavior as the decorated method.
raise
finally:
# Save logging data in the database
....
hope this will help to understand the use of re-raise
Typically in a try-catch model, any uncaught exception will automatically be thrown (raised?). Catching the exception only to re-throw it may be in the spirit Allman style coding, but serves no functional purpose.
Uh, Imagine
def something(a,b):
try:
// do stuff
except SomethingSpecificToThisFunction:
//handle
except: //Everything else, should likely be handled somewhere else
raise
try:
something("a","b")
except e:
Log(e)
Then again its default behaviour anyways, so might just want to leave it out
There are some approaches with such technics in multithread enviroment. For example to throw something to upper stack level.
This question already has answers here:
Is it better to use an exception or a return code in Python?
(6 answers)
Python: Throw Exception or return None? [closed]
(3 answers)
Closed 1 year ago.
What's better practice in a user-defined function in Python: raise an exception or return None? For example, I have a function that finds the most recent file in a folder.
def latestpdf(folder):
# list the files and sort them
try:
latest = files[-1]
except IndexError:
# Folder is empty.
return None # One possibility
raise FileNotFoundError() # Alternative
else:
return somefunc(latest) # In my case, somefunc parses the filename
Another option is leave the exception and handle it in the caller code, but I figure it's more clear to deal with a FileNotFoundError than an IndexError. Or is it bad form to re-raise an exception with a different name?
It's really a matter of semantics. What does foo = latestpdf(d) mean?
Is it perfectly reasonable that there's no latest file? Then sure, just return None.
Are you expecting to always find a latest file? Raise an exception. And yes, re-raising a more appropriate exception is fine.
If this is just a general function that's supposed to apply to any directory, I'd do the former and return None. If the directory is, e.g., meant to be a specific data directory that contains an application's known set of files, I'd raise an exception.
I would make a couple suggestions before answering your question as it may answer the question for you.
Always name your functions descriptive. latestpdf means very little to anyone but looking over your function latestpdf() gets the latest pdf. I would suggest that you name it getLatestPdfFromFolder(folder).
As soon as I did this it became clear what it should return.. If there isn't a pdf raise an exception. But wait there more..
Keep the functions clearly defined. Since it's not apparent what somefuc is supposed to do and it's not (apparently) obvious how it relates to getting the latest pdf I would suggest you move it out. This makes the code much more readable.
for folder in folders:
try:
latest = getLatestPdfFromFolder(folder)
results = somefuc(latest)
except IOError: pass
Hope this helps!
I usually prefer to handle exceptions internally (i.e. try/except inside the called function, possibly returning a None) because python is dynamically typed. In general, I consider it a judgment call one way or the other, but in a dynamically typed language, there are small factors that tip the scales in favor of not passing the exception to the caller:
Anyone calling your function is not notified of the exceptions that can be thrown. It becomes a bit of an art form to know what kind of exception you are hunting for (and generic except blocks ought to be avoided).
if val is None is a little easier than except ComplicatedCustomExceptionThatHadToBeImportedFromSomeNameSpace. Seriously, I hate having to remember to type from django.core.exceptions import ObjectDoesNotExist at the top of all my django files just to handle a really common use case. In a statically typed world, let the editor do it for you.
Honestly, though, it's always a judgment call, and the situation you're describing, where the called function receives an error it can't help, is an excellent reason to re-raise an exception that is meaningful. You have the exact right idea, but unless you're exception is going to provide more meaningful information in a stack trace than
AttributeError: 'NoneType' object has no attribute 'foo'
which, nine times out of ten, is what the caller will see if you return an unhandled None, don't bother.
(All this kind of makes me wish that python exceptions had the cause attributes by default, as in java, which lets you pass exceptions into new exceptions so that you can rethrow all you want and never lose the original source of the problem.)
with python 3.5's typing:
example function when returning None will be:
def latestpdf(folder: str) -> Union[str, None]
and when raising an exception will be:
def latestpdf(folder: str) -> str
option 2 seem more readable and pythonic
(+option to add comment to exception as stated earlier.)
In general, I'd say an exception should be thrown if something catastrophic has occured that cannot be recovered from (i.e. your function deals with some internet resource that cannot be connected to), and you should return None if your function should really return something but nothing would be appropriate to return (i.e. "None" if your function tries to match a substring in a string for example).