views:

134

answers:

3

I have a method that will either return an object or None if the lookup fails. Which style of the following is better?

def get_foo(needle):
    haystack = object_dict()
    if needle not in haystack: return None
    return haystack[needle]

or,

def get_foo(needle):
    haystack = object_dict()
    try:
        return haystack[needle]
    except KeyError:
        # Needle not found
        return None

I'm undecided as to which is more more desirable myself. Another choice would be return haystack[needle] if needle in haystack else None, but I'm not sure that's any better.

+10  A: 

For this particular example, it looks like the dict method get is the most concise:

def get_foo(needle):
    haystack = object_dict()
    return haystack.get(needle)

In general, in Python, people tend to prefer try/except than checking something first - see the EAFP entry in the glossary. Note that many "test for membership" functions use exceptions behind the scenes.

I won't start a flamewar on the relative merits of multiple returns or the alternatives :)

detly
The EAFP entry you mentioned is what prompted the question, mostly. Thanks for the info on dict.get(), I wasn't aware that it handled this situation so well.
Daenyth
It's a common task — see also [defaultdict objects](http://docs.python.org/library/collections.html#defaultdict-objects). As for EAFP - not everyone follows it, but it's worth knowing what the common conventions are. I'm guilty of ignoring it myself when I feel it's appropriate.
detly
+2  A: 

if both do exactly the same, choose that one that you like the most and thats more readable - i like the second one, but both are good.

(maybe one if this is faster than the other one - so if preformance is realy important, test it and choose the faster one)

oezi
How on earth can you say 'both are good'? The first one does a lookup twice every time it's called: once to find out if the key is there, then again to get and return the value. That just seems plain dumb to me.
Don O'Donnell
@Don: That's a great point that I hadn't even really considered.
Daenyth
A: 

In every language I've used the first version is perferable. Exceptions are basically goto's in disguise with many of the same problems, so I don't use them if I can avoid it.

There is also a possible performance cost. I don't know about Python, but in many other languages there is a heavy cost for creating the exception that you are going to throw away on the next line.

Jonathan Allen
EVERY control structure is a `goto` in disguise. Comparing sophisticated and well-defined control structures to `goto` is meaningless. Also, many "test for membership" functions use exceptions behind the scenes.
detly
Regarding the speed aspect, I have not profiled to see which is faster, but my intuition tells me the try/except version may be faster in the common case (needle is found). The first version will test the if expression on every call, whereas the try/except one would only use the exception in the failure case.Please do let me know if I have some misunderstanding of the internals vs what I just described though.At any rate, it's not going to be a common call, so it's more for style/readability than speed.
Daenyth
@detly Most control structures don't have the "jump from anywhere" behavior that exceptions have. Your exit points are well defined in if-blocks and for-loops. It is only in try blocks that every line effectively becomes a goto.
Jonathan Allen
I see what you're saying, but there's still a contract. You can catch exceptions, you absolutely cannot catch a `goto`. Some languages have a `throws` declaration, but no such declaration exists for a `goto` (I just had a mental image of such a Java function — `public void Foo(int a) throws IOException goesto Bar {...`). Exceptions don't move execution to an arbitrary unrelated function — they will only propagate through the callers. (Do keep in mind that when I think of `goto`, I think of C and BASIC...)
detly