Using try vs if in python
在测试变量是否具有值时,是否有理由决定使用哪个
例如,有一个函数返回列表或不返回值。我想在处理之前检查一下结果。以下哪一项更可取?为什么?
1 2 3 4 | result = function(); if (result): for r in result: #process items |
或
1 2 3 4 5 6 | result = function(); try: for r in result: #process items except TypeError: pass; |
相关讨论:
检查python中是否存在成员
你经常听说python鼓励eafp风格("请求宽恕比允许更容易")而不是lbyl风格("三思而后行")。对我来说,这是一个效率和可读性的问题。
在您的示例中(假设函数不是返回一个列表或空字符串,而是返回一个列表或
要通过一些测量来支持这一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | >>> 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: a/b except ZeroDivisionError: pass") 0.0829463709378615 >>> timeit.timeit(setup="a=1;b=0", stmt="try: a/b except ZeroDivisionError: pass") 0.5070195056614466 >>> timeit.timeit(setup="a=1;b=1", stmt="if b!=0: a/b") 0.11940114974277094 >>> timeit.timeit(setup="a=1;b=0", stmt="if b!=0: a/b") 0.051202772912802175 |
所以,虽然一个
寓意:
- 使用
try/except 进行流量控制是完全正常的(和"Python式的"), - 但当
Exception 实际上是例外时,这是最有意义的。
从python文档中:
EAFP
Easier to ask for forgiveness than
permission. This common Python coding
style assumes the existence of valid
keys or attributes and catches
exceptions if the assumption proves
false. This clean and fast style is
characterized by the presence of many
try andexcept statements. The
technique contrasts with the LBYL
style common to many other languages
such as C.
函数不应返回混合类型(即列表或空字符串)。它应该返回一个值列表或者只是一个空列表。然后您就不需要测试任何东西,即您的代码折叠为:
1 2 | for r in function(): # process items |
如果我提供的代码乍一看不明显,您必须在代码示例之后阅读解释,请忽略我的解决方案。
我可以假设"无返回值"表示返回值为"无"?如果是,或者如果"no value"是假布尔值,则可以执行以下操作,因为您的代码本质上将"no value"视为"do not iterate":
1 2 | for r in function() or (): # process items |
如果
第二个示例被破坏了——代码永远不会抛出类型错误异常,因为您可以同时遍历字符串和列表。遍历空字符串或列表也是有效的-它将执行循环体零次。
Which of the following would be more preferable and why?
在这种情况下,最好是三思而后行。使用异常方法,类型错误可能发生在循环体的任何地方,它会被捕获并丢弃,这不是您想要的,并且会使调试变得棘手。
(不过,我同意布兰登·考夫曼的观点:不返回"无项目"而不返回空列表是不可能的。在Python中不应该看到Java编译器的一个令人不快的习惯。或者Java。
一般来说,我的印象是例外情况应该保留在例外情况下。如果预计
我想到了(更常见的)情景:
1 2 3 4 5 6 7 | # 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 |
代替等效物:
1 2 3 4 5 | ... try: file_counts[filename]+=1 except KeyError: file_counts[filename]=1 |
Bobince明智地指出,包装第二个案例也可以在循环中捕获类型错误,这不是您想要的。如果你真的想使用一个尝试,你可以在循环之前测试它是否是可测试的。
1 2 3 4 5 6 7 8 | result = function(); try: it = iter(result) except TypeError: pass else: for r in it: #process items |
如你所见,它相当难看。我不建议这样做,但为了完整起见,应该提及它。
就性能而言,对通常不引发异常的速度比每次使用if语句都快。因此,决定取决于例外情况的概率。
一般来说,您不应该使用Try/Catch或任何异常处理工具来控制流。尽管后台迭代是通过引发