which style is preferred?

徘徊边缘 提交于 2019-12-10 02:38:11

问题


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?


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


Neither.

return d.get(c, 'N/A')



回答5:


I'm with David on this one:

def f2(c):
   d = {
        "USA": "N.Y.",
        "China": "Shanghai"
       }

   return d.get(c, "N/A")

...is exactly how I'd write it.

To address your other options:

In 'f1()', there's nothing wrong with this, per se, but dictionaries have a get() method for pretty much this exact use case: "get this from the dict, and if it's not there, return this other thing instead". That's all your code is saying, using get() is just more concise.

In 'f2()', using 'except' by itself like that is frowned upon, and in addition, you don't really do anything useful in response to the exception -- in your case the calling code will never know there was an exception. So why use the construct if it doesn't add value to your function or the code that calls it?




回答6:


I see people using "get", which I recommend. However, if you find yourself in a similar situation in the future, catch the exception you mean:

try:
    return d[k]
except KeyError:
    return "N/A"

This way, other exceptions (including KeyboardInterrupt) don't get caught. You almost never want to catch KeyboardInterrupt.




回答7:


I agree that in this case, dict.get is the best solution.

In general, I think your choice will depend on how likely the exceptions are. If you expect the key lookups to mostly pass, then the try/catch is a better choice IMO. Similarly, if they will be failing often, an if statement is better.

Performance of exceptions versus attribute lookups is not so different in Python, so I'd worry more about the logic of using exceptions/look-before-you-leap than about the performance aspects.



来源:https://stackoverflow.com/questions/2114540/which-style-is-preferred

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!