在Python中,我不时地看到块:

try:
   try_this(whatever)
except SomeException as exception:
   #Handle exception
else:
   return something

try-except-else存在的原因是什么?

我不喜欢这种编程,因为它使用异常来执行流控制。然而,如果它被包含在语言中,一定有一个很好的理由,不是吗?

我的理解是,异常不是错误,它们只应该用于异常情况(例如,我试图将一个文件写入磁盘,但没有更多的空间,或者我可能没有权限),而不是用于流量控制。

通常我是这样处理异常的:

something = some_default_value
try:
    something = try_this(whatever)
except SomeException as exception:
    #Handle exception
finally:
    return something

或者如果我真的不想在异常发生时返回任何东西,那么:

try:
    something = try_this(whatever)
    return something
except SomeException as exception:
    #Handle exception

当前回答

在python中使用try-except-else是一个好习惯吗?

答案是,这取决于上下文。如果你这样做:

d = dict()
try:
    item = d['item']
except KeyError:
    item = 'default'

这说明您不是很了解Python。这个功能封装在字典中。获得方法:

item = d.get('item', 'default')

try/except块是一种视觉上更加混乱和冗长的方式,它可以用原子方法在一行中有效地执行。在其他情况下也是如此。

然而,这并不意味着我们应该避免所有的异常处理。在某些情况下,最好避免竞争条件。不要检查文件是否存在,只是尝试打开它,并捕获相应的IOError。出于简单性和可读性的考虑,请尝试将其封装或适当地提取出来。

阅读Python的禅宗,了解有一些原则处于紧张状态,并警惕过分依赖其中任何一条陈述的教条。

其他回答

在python中使用try-except-else是一个好习惯吗?

答案是,这取决于上下文。如果你这样做:

d = dict()
try:
    item = d['item']
except KeyError:
    item = 'default'

这说明您不是很了解Python。这个功能封装在字典中。获得方法:

item = d.get('item', 'default')

try/except块是一种视觉上更加混乱和冗长的方式,它可以用原子方法在一行中有效地执行。在其他情况下也是如此。

然而,这并不意味着我们应该避免所有的异常处理。在某些情况下,最好避免竞争条件。不要检查文件是否存在,只是尝试打开它,并捕获相应的IOError。出于简单性和可读性的考虑,请尝试将其封装或适当地提取出来。

阅读Python的禅宗,了解有一些原则处于紧张状态,并警惕过分依赖其中任何一条陈述的教条。

哦,你是对的。在Python中,try/except后面的else很难看。它指向另一个不需要的流控制对象:

try:
    x = blah()
except:
    print "failed at blah()"
else:
    print "just succeeded with blah"

一个完全等价的词是:

try:
    x = blah()
    print "just succeeded with blah"
except:
    print "failed at blah()"

这比else子句清楚得多。try/except之后的else并不经常被写入,因此需要花一些时间来确定其含义。

仅仅因为你能做一件事,并不意味着你应该做一件事。

许多特性被添加到语言中,因为有人认为它可能会派上用场。问题是,功能越多,事物就越不清晰和明显,因为人们通常不使用那些花哨的东西。

这只是我的5分钱。我必须跟在后面,清理许多由大学一年级的开发人员编写的代码,这些开发人员自认为很聪明,想以一种超级紧凑、超级高效的方式编写代码,但这样做只会让以后尝试和阅读/修改时变得一团糟。我每天都为可读性投票,周日两次。

我想说,仅仅因为没有人发表过这种观点

避免在try/except中使用else子句,因为大多数人都不熟悉它们

与关键字try、except和finally不同,else子句的含义不是不言而喻的;可读性较差。因为它不经常使用,它会导致阅读代码的人想要再次检查文档,以确保他们理解了发生了什么。

(我写这个答案正是因为我在我的代码库中发现了一个try/except/else,它引起了一个wtf时刻,迫使我做一些谷歌搜索)。

因此,无论我在哪里看到类似OP示例的代码:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
else:
    # do some more processing in non-exception case
    return something

我更倾向于重构

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
    return  # <1>
# do some more processing in non-exception case  <2>
return something

<1>显式返回,清楚地表明,在异常情况下,我们已经完成了工作 <2>作为一个不错的小副作用,原来在else块中的代码被降低了一级。

这是我关于如何理解Python中的try-except-else-finally块的简单代码片段:

def div(a, b):
    try:
        a/b
    except ZeroDivisionError:
        print("Zero Division Error detected")
    else:
        print("No Zero Division Error")
    finally:
        print("Finally the division of %d/%d is done" % (a, b))

我们试试div 1/1:

div(1, 1)
No Zero Division Error
Finally the division of 1/1 is done

我们试试div 1/0

div(1, 0)
Zero Division Error detected
Finally the division of 1/0 is done

Python不赞同异常只用于异常情况的想法,事实上,习惯用法是“请求原谅,而不是许可”。这意味着使用异常作为流控制的常规部分是完全可以接受的,实际上是被鼓励的。

这通常是一件好事,因为以这种方式工作有助于避免一些问题(一个明显的例子是,经常避免竞争条件),而且它往往使代码更具可读性。

假设您有这样一种情况,需要处理一些用户输入,但默认值已经处理完毕。尝试:……除了:…其他:…结构使得代码可读性非常强:

try:
   raw_value = int(input())
except ValueError:
   value = some_processed_value
else: # no error occured
   value = process_value(raw_value)

与它在其他语言中的工作方式进行比较:

raw_value = input()
if valid_number(raw_value):
    value = process_value(int(raw_value))
else:
    value = some_processed_value

注意它的优点。没有必要检查值是否有效并分别解析它,它们只执行一次。代码也遵循一个更有逻辑的顺序,主代码路径是第一个,然后是“如果它不起作用,就这样做”。

这个例子自然有点做作,但它显示了这种结构的一些情况。