当测试变量是否具有值时,是否有一个基本原理来决定使用哪个try或if结构?

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

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

or

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

相关讨论:

检查Python中的成员是否存在


当前回答

一般来说,我得到的印象是例外应该为特殊情况保留。如果期望结果永远不为空(但可能为空,例如,如果磁盘崩溃等等),则第二种方法是有意义的。另一方面,如果一个空结果在正常条件下是完全合理的,那么使用If语句测试它更有意义。

我想到了(更常见的)场景:

# 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

其他回答

你的第二个例子是坏的——代码永远不会抛出TypeError异常,因为你可以遍历字符串和列表。遍历空字符串或列表也是有效的——它将执行循环体0次。

下面哪个更可取,为什么?

在这种情况下,三思而后行更可取。使用异常方法,TypeError可能出现在循环体的任何地方,它会被捕获并丢弃,这不是您想要的,并且会使调试变得棘手。

(我同意Brandon Corfman的观点:为“没有项目”返回None而不是空列表是错误的。这是Java编码员的一个不愉快的习惯,在Python中不应该看到。或Java)。

一般来说,我得到的印象是例外应该为特殊情况保留。如果期望结果永远不为空(但可能为空,例如,如果磁盘崩溃等等),则第二种方法是有意义的。另一方面,如果一个空结果在正常条件下是完全合理的,那么使用If语句测试它更有意义。

我想到了(更常见的)场景:

# 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,这不是您想要的。如果你真的想使用try,你可以在循环之前测试它是否可迭代

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

如你所见,它相当难看。我不建议这样做,但为了完整起见,应该提到它。

一般的经验法则是,永远不要使用try/catch或任何异常处理来控制流。即使幕后的迭代是通过引发StopIteration异常来控制的,您仍然应该更喜欢第一个代码片段而不是第二个。