Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

which style is preferred?

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?

like image 844
Dyno Fu Avatar asked Jan 22 '10 02:01

Dyno Fu


4 Answers

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.

like image 164
David Raznick Avatar answered Nov 14 '22 09:11

David Raznick


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.

like image 36
paxdiablo Avatar answered Nov 14 '22 10:11

paxdiablo


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.

like image 42
Jon W Avatar answered Nov 14 '22 09:11

Jon W


Neither.

return d.get(c, 'N/A')
like image 7
Ignacio Vazquez-Abrams Avatar answered Nov 14 '22 10:11

Ignacio Vazquez-Abrams