Option 1:
def f1(c):
d = {
"USA": "N.Y.",
"China": "Shanghai"
}
if c in d:
return d[c]
return "N/A"
Option 2:
def f2(c):
d = {
"USA": "N.Y.",
"China": "Shanghai"
}
try:
return d[c]
except:
return "N/A"
So that I can then call:
for c in ("China", "Japan"):
for f in (f1, f2):
print "%s => %s" % (c, f(c))
The options are to either determine whether the key is in directory before hand (f1), or just fallback to the exception (f2). Which one is preferred? Why?
Neither, I would go for
def f2(c):
d = {
"USA": "N.Y.",
"China": "Shanghai"
}
return d.get(c, "N/A")
This way is shorter and "get" is designed for the job.
Also an except without an explicit exception is bad pratice, so use except KeyError:
not just except.
Exceptions do not have much overhead in python. It is generally better to use them if there are not better alternatives or sometimes even when it saves an attribute lookup (to use instead of hasattr).
Edit: to clear up general point about exceptions.
paxdiablo is correct on the general point. Python is mainly designed for "its easier to ask forgivness then permission" i.e try then see what fails (exceptions), then "look before you leap" see whats there and then apply. This is because attribute lookup in python can be expensive, so calling the same stuff again (to check boundries) is a waste of resources. However, internal stuff in python has normally got nicer helpers so its better to use them.
In general terms (not necessarily Python), I tend to prefer the "try-then-tell-me-if-it-went-wrong" method (exceptions) in all but the simplest cases. This is because, in threaded environments or during database access, the underlying data can change between the key check and the value extraction.
If you're not changing the associative array outside of the current thread, then you can do the "check-first-then-extract" method.
But that's for the general case. Here, specifically, you can use the get
method which allows you to specify a default if the key doesn't exist:
return d.get (c, "N/A")
I'll clarify what I stated in the first paragraph. In situations where the underlying data can change between checking and using, you should always use an exception-type operation (unless you have an operation that will not cause a problem, such as d.get()
, mentioned above). Consider for example the following two thread time-lines:
+------------------------------+--------------------+
| Thread1 | Thread2 |
+------------------------------+--------------------+
| Check is NY exists as a key. | |
| | Delete NY key/val. |
| Extract value for NY. | |
+------------------------------+--------------------+
When thread 1 attempts to extract the value, it will get an exception anyway, so you may as well just code for the possibility and remove the initial check.
The comment about databases is also relevant since that's another situation where the underlying data can change. That's why I tend to prefer atomic SQL (where possible) rather than something like getting a list of keys then processing them with individual statements.
Typically, exceptions carry some overhead, and are meant for truly 'exceptional' cases. In this case, this sounds like a normal part of the execution, not an 'exceptional' or 'error' state.
In general, I think your code will benefit by using the "if/else" convention, and saving exceptions for only when they are truly needed.
Neither.
return d.get(c, 'N/A')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With