使用尝试与如果在Python中

当testingvariables有一个值时, if有理由决定try使用哪一个或者使用什么构造?

例如,有一个函数返回一个列表或不返回一个值。 我想在处理之前检查结果。 以下哪一项更可取?为什么?

 result = function(); if (result): for r in result: #process items 

要么

 result = function(); try: for r in result: #process items except TypeError: pass; 

相关讨论:

在Python中检查成员存在

你经常听说Python鼓励EAFP风格(“比容许更容易要求原谅”),而不是LBYL风格(“在你跳跃之前看”)。 对我来说,这是一个效率和可读性的问题。

在你的例子中(比如说,不是返回一个列表或一个空string,函数是返回一个列表或None ),如果你期望99%的时间result实际上包含可迭代的东西,我会使用try/except方法。 如果例外确实是例外,那将会更快。 如果resultNone超过50%的时间,那么使用if可能会更好。

为了支持这几个测量:

 >>> import timeit >>> timeit.timeit(setup="a=1;b=1", stmt="a/b") # no error checking 0.06379691968322732 >>> timeit.timeit(setup="a=1;b=1", stmt="try:\na/b\nexcept ZeroDivisionError:\n pass") 0.0829463709378615 >>> timeit.timeit(setup="a=1;b=0", stmt="try:\na/b\nexcept ZeroDivisionError:\n pass") 0.5070195056614466 >>> timeit.timeit(setup="a=1;b=1", stmt="if b!=0:\na/b") 0.11940114974277094 >>> timeit.timeit(setup="a=1;b=0", stmt="if b!=0:\na/b") 0.051202772912802175 

所以, if语句总是花费你的成本,那么几乎可以设置一个try/except块。 但是,实际发生Exception时,成本要高得多。

道德:

  • 使用try/exceptstream量控制try/except ,完全可以(和“pythonic”),
  • 但是当Exception实际上是例外的时候,这是最有意义的。

从Python文档:

EAFP

比容许更容易要求宽恕。 这种常见的Python编码风格假设存在有效的键或属性,并且如果假设certificate是错误的,则捕获exception。 这种干净而快速的风格的特点是存在许多tryexcept声明。 该技术与许多其他语言如C.的LBYL风格形成对比

你的函数不应该返回混合types(即列表或空string)。 它应该返回一个值列表或只是一个空的列表。 那么你不需要testing任何东西,即你的代码崩溃到:

 for r in function(): # process items 

如果我提供的代码乍看之下不明显,并且必须阅读代码示例之后的说明,请忽略我的解决scheme。

我可以假设“没有返回值”是指返回值是无? 如果是,或者如果“no value”为false,则可以执行以下操作,因为代码基本上将“no value”视为“不要迭代”:

 for r in function() or (): # process items 

如果function()返回的不是真的东西,你遍历空元组,即你不运行任何迭代。 这本质上是LBYL。

你的第二个例子被破坏 – 代码将永远不会抛出TypeErrorexception,因为你可以遍历string和列表。 迭代空string或列表也是有效的 – 它将执行循环体零次。

以下哪一项更可取?为什么?

在这之前,先看看你的飞跃是否可取。 使用exception的方法,TypeError可能发生在你的循环体内的任何地方,它会被抓住并扔掉,这不是你想要的,并且会使debugging变得棘手。

(但是我同意Brandon Corfman的观点:没有任何项目而不是空的列表返回None是不成立的,这是Java编程人员不习惯的习惯,不应该在Python中看到。

一般来说,我得到的印象是,特殊情况下应该保留例外。 如果预期的result永远不会是空的(但可能是,如果,例如,磁盘崩溃等),第二种方法是有道理的。 另一方面,如果一个空的result在正常情况下是完全合理的,那么用一个if语句进行testing就更有意义了。

我想到了(更常见)的情况:

 # keep access counts for different files file_counts={} ... # got a filename somehow if filename not in file_counts: file_counts[filename]=0 file_counts[filename]+=1 

而不是相当的:

 ... try: file_counts[filename]+=1 except KeyError: file_counts[filename]=1 

bobince明智地指出,包装第二种情况也可以在循环中捕获TypeErrors,这不是你想要的。 如果你真的想尝试一下,你可以在循环之前testing它是否可迭代

 result = function(); try: it = iter(result) except TypeError: pass else: for r in it: #process items 

正如你所看到的,这相当丑陋。 我不build议这样做,但应该提到完整性。

就性能而言,对于通常不会引发exception的代码使用try块比每次使用if语句更快。 所以,这个决定取决于例外情况的可能性。

一般来说,你不应该使用try / catch或者任何exception处理来控制stream。 即使后台迭代通过引发StopIterationexception来控制,仍然应该优先select第一个代码片段。