Reputation: 86592
This particular example relates to Django in Python, but should apply to any language supporting exceptions:
try:
object = ModelClass.objects.get(search=value)
except DoesNotExist:
pass
if object:
# do stuff
The Django model class provides a simple method get which allows me to search for one and only one object from the database, if it finds more or less it raises an exception. If can find zero or more with an alternative filter method, which returns a list:
objects = ModelClass.objects.filter(search=value)
if len(objects) == 1:
object = objects[0]
# do stuff
Am I overly averse to exceptions? To me the exception seems a little wasteful, at a guess, a quarter-to-a-half of the time will be 'exceptional'. I'd much prefer a function that returns None on failure. Would I be better to use Django's filter method and process the list myself?
Upvotes: 8
Views: 2344
Reputation: 14090
I disagree with the above comments that an exception is inefficient in this instance, especially since it's being used in an I/O bound operation.
Here's a more realistic example using Django with an in-memory sqlite database. Each of a 100 different queries was run, then averaged for each of a 100 runs. Although I doubt if it would matter, I also changed the order of execution.
With ObjectDoesNotExist... 0.102783939838
Without exception ........ 0.105322141647
With ObjectDoesNotExist... 0.102762134075
Without exception ........ 0.101523952484
With ObjectDoesNotExist... 0.100004930496
Without exception ........ 0.107946784496
You can instrument this in your own Django environment, but I doubt if your time is well spent avoiding this exception.
Upvotes: 2
Reputation: 198847
Believe it or not, this actually is an issue that is a bit different in each language. In Python, exceptions are regularly thrown for events that aren't exceptional by the language itself. Thus I think that the "you should only throw exceptions under exceptional circumstances" rule doesn't quite apply. I think the results you'll get on this forum will be slanted towards that point of view though, considering the high number of .Net programmers (see this question) for more info on that).
At a very minimum, I'd better not catch anyone who sticks to that rule ever using a generator or a for loop in Python (both of which involve throwing exceptions for non-exceptional circumstances).
Upvotes: 11
Reputation: 683
I agree with the other answer but I wanted to add that exception passing like this is going to give you a very noticeable performance hit. Highly recommended that you check to see if the result exists (if that's what filter does) instead of passing on exceptions.
Edit:
In response to request for numbers on this, I ran this simple test...
import time
def timethis(func, list, num):
st=time.time()
for i in xrange(0,1000000):
try:
func(list,num)
except:
pass
et = time.time()
print "Took %gs" % (et-st)
def check(list, num):
if num < len(list):
return list[num]
else:
return None
a=[1]
timethis(check, a, 1)
timethis(lambda x,y:x[y], a, 1)
And the output was..
Took 0.772558s
Took 3.4512s
HTH.
Upvotes: 3
Reputation: 202715
There's a big schism in programming languages around the use of exceptions.
The majority view is that exceptions should be exceptional. In most languages with exceptions, transfer of control by exception is considerably more expensive than by procedure return, for example.
There is a strong minority view that exceptions are just another control-flow construct, and they should be cheap. The Standard ML of New Jersey and Objective Caml compilers subscribe to that view. If you have cheap exceptions you can code some fancy backtracking algorithms in ways that are more difficult to code cleanly using other mechanisms.
I've seen this debate repeated many times for new language designs, and almost always, the winner decides that exceptions should be expensive and rare. When you care about performanced, you'd be wise to program with this in mind.
Upvotes: 8
Reputation: 6049
Aversion to excpetions is a matter of opinion - however, if there's reason to believe that a function or method is going to be called many times or called rapidly, exceptions will cause a significant slowdown. I learned this from my previous question, where I was previously relying on a thrown exception to return a default value rather than doing parameter checking to return that default.
Of course, exceptions can still exist for any reason, and you shouldn't be afraid to use or throw one if necessary - especially ones that could potentially break the normal flow of the calling function.
Upvotes: 2
Reputation: 136727
The clue is in the name - exceptions should be exceptional.
If you always expect the item will exist then use get
, but if you expect it not to exist a reasonable proportion of the time (i.e. it not existing is an expected result rather than an exceptional result) then I'd suggest using filter
.
So, seeing as you indicated that between 1 in 2 and 1 in 4 are expected not to exist, I'd definitely write a wrapper around filter
, as that's definitely not an exceptional case.
Upvotes: 5
Reputation: 376052
The answer will depend on the intent of the code. (I'm not sure what your code sample was meant to do, the pass in the exceptional case is confusing, what will the rest of the code do with object
variable to work with?)
Whether to use exceptions or to use a method which treat the case as non-exceptional is a matter of taste in many cases. Certainly if the real code in the except clause is as complicated as the filter method you'd have to use to avoid the exception, then use the filter method. Simpler code is better code.
Upvotes: 2