让我们考虑这个例子 - 代码返回列表None
中的第一个li
值的索引(如果存在)或最后一个元素的索引{{1 } {}不存在于None
。
我可以检查列表中的“无”,但使用ifs并不是首选方式 - Dive Into Python鼓励使用异常,因为它们被认为更快并且使代码更清晰(请参阅this问题)。所以我提出了三种方法:
1
li
在try / except块中声明了 try:
my_index = li.index(None)
except ValueError:
my_index = len(li) - 1
print my_index
。减少行数,无冗余声明。可能的问题 - 不同的异常类型将导致无法创建my_index
并导致my_index
上的脚本崩溃。
2
print
在try / except之前声明了 my_index = None # or anything else
try:
my_index = li.index(None)
except ValueError:
my_index = len(li) - 1
print my_index
,并且无论发生什么异常,都会分配一个值。缺点 - 更多线条,看起来多余。
3。 编辑:无法工作 - 无论尝试/除结果
my_index
优点 - 始终有效(或至少我认为如此)。缺点 - 我从未见过有人使用try:
my_index = li.index(None)
except ValueError:
my_index = len(li) - 1
finally:
my_index = None # or anything else
print my_index
来完成我的整个Python体验,这种情况必然会发生。
哪种方法被认为是首选和pythonic方式?也许有更好的解决方案?
答案 0 :(得分:2)
try: my_index = li.index(None) except ValueError: my_index = len(li) - 1 print my_index
可能存在的问题 - 不同的异常类型将导致
my_index
无法创建
呃,不。如果引发任何其他异常,则整个代码块将被中止,因为异常会冒泡到调用者。因此,如果引发除ValueError
之外的任何其他异常类型,则永远不会执行print
。这是一个非常理智的行为:您处理预期的错误并且可以处理,并让其他错误导致整个块中止,可能是整个脚本。这是您想要的最安全,最简洁的解决方案。
答案 1 :(得分:1)
第三种选择不起作用。查看finally
上的文档
(强调我的):
在离开try语句之前总是执行finally子句,是否发生了异常。
所以在第三个选项中,无论发生什么,my_index
总是没有。
这给我们留下了第一个和第二个选项。值得注意的是,第二个是你在大多数静态类型语言中看到的。然而,Python稍微宽松一点,允许使用任何一个选项。
我认为您关于非ValueError
的异常的论点无效。另一个例外是暂停执行并返回调用者,因此永远不会达到打印。所以第一个解决方案应该可以正常工作。
答案 2 :(得分:1)
++正如@deceze注意到的那样,除了ValueError:只会捕获这个类的错误,而不会捕获其他错误。
如果您确实需要以不同方式处理不同的错误情况,可以提供更多例外条款:
try:
...
except (ValueError, TypeError, ...):
...
中除之外的序列也受支持:
{{1}}
+++如果传递空列表,您应该考虑代码需要返回什么:-1?提出异常?
答案 3 :(得分:0)
我认为这是不使用例外的示例。虽然Python使用异常作为"通常"编程构造以降低复杂性,这是我认为增加复杂性的一个案例。您的代码告诉我my_index
必须在这些行之后保留一个值,并且您希望li
是可迭代的,即使在异常发生时也是如此。这个例外ValueError
是None
不在列表中的结果,是一个额外的复杂性,只有按惯例才能理解 - 而且,你确定它不是IndexError
可能被抛出?你看,恕我直言的构造
if None in li: my_index = li.index(None)
else : my_index = len(li) - 1
不会抛出半年内遇到此代码的程序员,也许是你自己,在理解你的程序逻辑的轨道上,而有例外的版本将导致额外的脑力劳动,如果你的预期提出了问题可能的例外和反应是完整和正确的。只有当这是一个真正非常重要的性能代码时,你才应该试图避开双重搜索。