哪种款式首选?

时间:2010-01-22 02:21:37

标签: python exception coding-style

选项1:

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

  if c in d:
    return d[c]

  return "N/A"

选项2:

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

  try:
    return d[c]
  except:
    return "N/A"

然后我可以打电话:

for c in ("China", "Japan"):
  for f in (f1, f2):
    print "%s => %s" % (c, f(c))

选项是确定密钥是否在预先存在于目录中(f1),或者只是回退到异常(f2)。哪一个更受欢迎?为什么呢?

7 个答案:

答案 0 :(得分:21)

两者都没有,我会选择

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

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

这种方式更短,“get”就是为这项工作而设计的。

另外,没有明确异常的情况也是不好的,所以不要只使用except KeyError:

异常在python中没有太多开销。如果没有更好的替代方案或有时甚至在保存属性查找(使用而不是hasattr)时使用它们通常更好。

编辑以澄清有关例外的一般观点。

paxdiablo在一般方面是正确的。 Python主要是为了“它更容易请求原谅然后允许”,即尝试然后查看失败(例外),然后“在你跳跃之前看”然后看看那里然后申请。这是因为python中的属性查找可能很昂贵,因此再次调用相同的东西(检查边界)是浪费资源。但是,python中的内部函数通常会有更好的帮助程序,所以最好使用它们。

答案 1 :(得分:11)

一般而言(不一定是Python),除了最简单的情况外,我倾向于选择“尝试然后告诉我,如果它错了”方法(例外)。这是因为,在线程环境中或在数据库访问期间,基础数据可以在密钥检查和值提取之间发生变化。

如果您没有更改当前线程之外的关联数组,那么您可以执行“先检查然后提取”方法。

但这是一般情况。在这里,具体来说,您可以使用get方法,该方法允许您在密钥不存在时指定默认值:

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

我将澄清我在第一段中所述的内容。在基础数据可以在检查和使用之间更改的情况下,您应该始终使用异常类型操作(除非您有一个不会导致问题的操作,例如d.get(),上文提到的)。例如,考虑以下两个线程时间线:

+------------------------------+--------------------+
| Thread1                      | Thread2            |
+------------------------------+--------------------+
| Check is NY exists as a key. |                    |
|                              | Delete NY key/val. |
| Extract value for NY.        |                    |
+------------------------------+--------------------+

当线程1尝试提取值时,无论如何它都会得到一个例外,所以你也可以只编写可能性的代码并删除初始检查。

关于数据库的评论也是相关的,因为这是基础数据可以改变的另一种情况。这就是为什么我倾向于选择原子SQL(在可能的情况下),而不是像获取密钥列表然后用单独的语句处理它们。

答案 2 :(得分:9)

通常情况下,异常带来一些开销,并且意味着真正“特殊”的情况。在这种情况下,这听起来像执行的正常部分,而不是“异常”或“错误”状态。

一般来说,我认为您的代码将受益于使用“if / else”约定,并仅在真正需要时保存例外。

答案 3 :(得分:7)

都不是。

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

答案 4 :(得分:4)

我和大卫在一起:

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

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

...正是我写的方式。

解决您的其他选择:

在'f1()'中,这本身并没有什么问题,但字典对于这个确切的用例有一个get()方法:“从dict中获取它,如果不存在,请返回此而另一件事“。这就是你的所有代码所说的,使用get()更简洁。

在'f2()'中,使用'except'本身就是不赞成的,此外,你并没有真正做任何有用的事情来响应异常 - 在你的情况下,调用代码永远不会知道有一个例外。那么为什么使用构造如果它没有为你的函数或调用它的代码增加价值呢?

答案 5 :(得分:1)

我看到人们使用“get”,我推荐。但是,如果您将来发现自己处于类似情况,请抓住您的意思:

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

这样,其他异常(包括KeyboardInterrupt)就不会被捕获。你几乎不想抓住KeyboardInterrupt

答案 6 :(得分:0)

我同意在这种情况下,dict.get是最好的解决方案。

一般来说,我认为您的选择将取决于例外的可能性。如果您希望密钥查找主要通过,那么try / catch是更好的选择IMO。同样,如果它们经常失败,那么if语句会更好。

异常与属性查找的性能在Python中并没有那么不同,所以我更担心使用异常/先行先跳的逻辑而不是性能方面。