4 ms·
The Python community generally advocates an "it's easier to ask for forgiveness than permission" coding style. When faced with a condition of the form "if condi
by samdk 14y ago
The Python community generally advocates an "it's easier to ask for forgiveness than permission" coding style. When faced with a condition of the form "if condition a holds, do b, else c", it's very often a better idea to do "let's try b, and do c in case b fails because condition a didn't hold".
In this case it's better because you can avoid computing an extra hash of the object in cases where it's already a key of the dictionary. This may seem like a silly optimization, but it can very easily add up if you're accessing existing elements most of the time--I once had a bit of code that went 60x faster when I replaced an if-else with a try-except.
In other cases it can be even more beneficial. Say you're opening a file. One approach to avoid errors would be to check if a file exists first. This is error-prone because the file might cease to exist in between the 'if' and the 'open' statements, and now you have no code written to handle the error. Using try-except will ensure that you actually handle the error intelligently.
This isn't to say there's never a good reason to use an 'if' to check things, just that if you can do it in one step instead of two, one is usually better.
- gbog 14y agoAgree with that "try except" is better than "if else" for file handling ("with" is even better). I am not sure if "try except" is really faster than "if else" in some edge cases in a memoization context, as you claim. What I am sure is that in a didactic context, where you want people to understand code, something like: if args not in stored_results: stored_results[args] = fn(*args) return stored_results[args] is much better than that (from the OP): try: # try to get the cached result return stored_results[args] except KeyError: # nothing was cached for those args. let's fix that. result = stored_results[args] = fn(*args) return result
- SpiderX 14y agoFor a memoize function, try/except is perfect. You gain a slight speed benefit from function calls that are memoized as compared to the "if x not in y", and since memoize is all about speeding up repetitive function calls, it's the most optimal choice. Using the "if x not in y" you are giving up speed of the "x is actually in the y" in exchange for a cheaper than "except", however if you are memoizing a function, chances are that the function is going to eat up processing power making your optimization of the "exceptional case" at the expense of the "normal case" not worth it. As far as people understanding code - this is a common pattern in python code, try / except should be easy for anyone to understand.
- jmlane 14y agoOut of curiosity, in a situation where you are doing negligible condition testing, is try–except still considered "more performant" than if–else flow control? For some reason (and I'm going to do so reading to get clarity on this point), I have had the silly notion that throwing and handling exceptions can be costly.
- deleted 14y ago[deleted]
- sateesh 14y agoI don't think the try-except is 'more performant'. At least from the below benchmark test it doesn't seem to be so. >>> from timeit import timeit >>> timeit(setup='x=dict([(i,i*2) for i in range(10)])',stmt= """ if 20 in x: pass""") 0.07420943164572691 >>> timeit(setup='x=dict([(i,i*2) for i in range(10)])', stmt=""" try: x[20] except KeyError: pass""") 1.1514457843105674
- koenigdavidmj 14y agoI am on my phone and cannot test this, but the try:except: construct is optimised for the non-exceptional path. The latter is probably faster for x[0] than x[20].