Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中使用try-except-else是一种好的实践吗?_Python_Exception_Exception Handling_Try Catch - Fatal编程技术网

在Python中使用try-except-else是一种好的实践吗?

在Python中使用try-except-else是一种好的实践吗?,python,exception,exception-handling,try-catch,Python,Exception,Exception Handling,Try Catch,在Python中,我不时看到以下块: try: try_this(whatever) except SomeException as exception: #Handle exception else: return something 除了其他原因,尝试的原因是什么? 我不喜欢这种编程,因为它使用异常来执行流控制。然而,如果它被包含在语言中,肯定有一个很好的理由,不是吗 我的理解是,异常不是错误,它们只能用于异常情况(例如,我试图将文件写入磁盘,但没有更多空间,或者可能我没

在Python中,我不时看到以下块:

try:
   try_this(whatever)
except SomeException as exception:
   #Handle exception
else:
   return something
除了其他原因,尝试的原因是什么?

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

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

通常情况下,我将异常处理为:

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:。。。除了:。。。else:…
结构使代码非常可读:

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
注意优点。不需要检查值是否有效并单独解析它,它们只执行一次。代码也遵循一个更符合逻辑的进程,主代码路径是第一个,然后是“如果不起作用,就这样做”


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

您应该小心使用finally块,因为它与try中使用else块不同,除了。无论try except的结果如何,都将运行finally块

In [10]: dict_ = {"a": 1}

In [11]: try:
   ....:     dict_["b"]
   ....: except KeyError:
   ....:     pass
   ....: finally:
   ....:     print "something"
   ....:     
something
正如大家所注意到的,使用else块会使代码更具可读性,并且只有在未引发异常时才会运行

In [14]: try:
             dict_["b"]
         except KeyError:
             pass
         else:
             print "something"
   ....:
“我不知道这是否出于无知,但我不喜欢这样 这是一种编程,因为它使用异常来执行流控制。”

在Python世界中,使用异常进行流控制是常见且正常的

即使是Python核心开发人员也使用异常进行流控制,这种风格在语言中得到了充分的体现(例如,迭代器协议用于发出循环终止的信号)

此外,try-except样式用于防止某些构造中固有的竞争条件。例如,测试结果中的信息在您使用时可能已过时。同样,返回可能过时的信息。在这些情况下,将生成更可靠的代码

“我的理解是,例外不是错误,它们只应该 用于特殊情况”

在其他一些语言中,这一规则反映了他们的图书馆中反映的文化规范。“规则”还部分基于这些语言的性能考虑

Python文化规范有些不同。在许多情况下,必须对控制流使用异常。此外,在Python中使用异常不会像在某些编译语言中那样减慢周围代码和调用代码的速度(即,无论您是否实际使用异常,已经在每个步骤中实现了异常检查代码)

换句话说,您对“异常是针对异常的”的理解在其他一些语言中是有意义的,但在Python中是没有意义的

“但是,如果它包含在语言本身中,则必须有一个 这是很好的理由,不是吗?”

除了有助于避免竞争条件外,异常对于将错误处理拉到循环之外也非常有用。在解释语言中,这是一个必要的优化,因为解释语言不倾向于自动执行

此外,在处理问题的能力与出现问题的地方相去甚远的常见情况下,异常可以大大简化代码。例如,通常有顶级用户界面代码调用业务逻辑的代码,而业务逻辑又调用低级例程。低级例程中出现的情况(如数据库访问中唯一键的重复记录)只能在顶级代码中处理(如要求用户提供与现有键不冲突的新键)。对此类控制流使用异常允许中级例程完全忽略该问题,并与流控制的这一方面很好地解耦

有一个问题

另外,请参见下面的答案:

“除其他原因外,尝试存在的原因是什么?”

else子句本身很有趣。它在没有异常但在finally子句之前运行。这是其主要目的


如果没有else子句,在完成之前运行其他代码的唯一选项是将代码添加到try子句的笨拙做法。这是笨拙的,因为它有风险 引发代码中不受try块保护的异常

在完成之前运行额外的无保护代码的用例并不经常出现。因此,不要期望在已发布的代码中看到许多示例。这有点罕见

else子句的另一个用例是执行在没有异常发生时必须发生的操作,以及在处理异常时不发生的操作。例如:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
else:
    return something
try:
    try_this(whatever)
except SomeException as the_exception:
    handle_SomeException(the_exception)
    # Handle a instance of SomeException or a subclass of it.
except Exception as the_exception:
    generic_handle(the_exception)
    # Handle any other exception that inherits from Exception
    # - doesn't include GeneratorExit, KeyboardInterrupt, SystemExit
    # Avoid bare `except:`
else: # there was no exception whatsoever
    return something()
    # if no exception, the "something()" gets evaluated,
    # but the return will not be executed due to the return in the
    # finally block below.
finally:
    # this block will execute no matter what, even if no exception,
    # after "something" is eval'd but before that value is returned
    # but even if there is an exception.
    # a return here will hijack the return functionality. e.g.:
    return True # hijacks the return in the else clause above
recip=float('Inf')
尝试:
往复式=1/f(x)
除零误差外:
logging.info('无限结果')
其他:
logging.info('有限结果')
另一个例子出现在unittest Runner中:

try:
    tests_run += 1
    run_testcase(case)
except Exception:
    tests_failed += 1
    logging.exception('Failing test case: %r', case)
    print('F', end='')
else:
    logging.info('Successful test case: %r', case)
    print('.', end='')
最后,try块中else子句最常见的用法是为了美化(对齐异常的outcom)
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()"
try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
else:
    return something
no_error = None
try:
    try_this(whatever)
    no_error = True
except SomeException as the_exception:
    handle(the_exception)
if no_error:
    return something
try:
    try_this(whatever)
except SomeException as the_exception:
    handle_SomeException(the_exception)
    # Handle a instance of SomeException or a subclass of it.
except Exception as the_exception:
    generic_handle(the_exception)
    # Handle any other exception that inherits from Exception
    # - doesn't include GeneratorExit, KeyboardInterrupt, SystemExit
    # Avoid bare `except:`
else: # there was no exception whatsoever
    return something()
    # if no exception, the "something()" gets evaluated,
    # but the return will not be executed due to the return in the
    # finally block below.
finally:
    # this block will execute no matter what, even if no exception,
    # after "something" is eval'd but before that value is returned
    # but even if there is an exception.
    # a return here will hijack the return functionality. e.g.:
    return True # hijacks the return in the else clause above
$ python -m pydoc exceptions
$ python -m pydoc builtins
BaseException
    Exception
        ArithmeticError
            FloatingPointError
            OverflowError
            ZeroDivisionError
        AssertionError
        AttributeError
        BufferError
        EOFError
        ImportError
            ModuleNotFoundError
        LookupError
            IndexError
            KeyError
        MemoryError
        NameError
            UnboundLocalError
        OSError
            BlockingIOError
            ChildProcessError
            ConnectionError
                BrokenPipeError
                ConnectionAbortedError
                ConnectionRefusedError
                ConnectionResetError
            FileExistsError
            FileNotFoundError
            InterruptedError
            IsADirectoryError
            NotADirectoryError
            PermissionError
            ProcessLookupError
            TimeoutError
        ReferenceError
        RuntimeError
            NotImplementedError
            RecursionError
        StopAsyncIteration
        StopIteration
        SyntaxError
            IndentationError
                TabError
        SystemError
        TypeError
        ValueError
            UnicodeError
                UnicodeDecodeError
                UnicodeEncodeError
                UnicodeTranslateError
        Warning
            BytesWarning
            DeprecationWarning
            FutureWarning
            ImportWarning
            PendingDeprecationWarning
            ResourceWarning
            RuntimeWarning
            SyntaxWarning
            UnicodeWarning
            UserWarning
    GeneratorExit
    KeyboardInterrupt
    SystemExit
try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
    raise
try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
    raise DifferentException from the_exception
try:
    y = 1 / x
except ZeroDivisionError:
    pass
else:
    return y
try:
    return 1 / x
except ZeroDivisionError:
    return None
import contextlib
with contextlib.suppress(ZeroDivisionError):
    return 1 / x
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)
No Zero Division Error
Finally the division of 1/1 is done
div(1, 0)
Zero Division Error detected
Finally the division of 1/0 is done
for i in range(3):
    try:
        y = 1 / i
    except ZeroDivisionError:
        print(f"\ti = {i}")
        print("\tError report: ZeroDivisionError")
    else:
        print(f"\ti = {i}")
        print(f"\tNo error report and y equals {y}")
    finally:
        print("Try block is run.")
    i = 0
    Error report: ZeroDivisionError
Try block is run.
    i = 1
    No error report and y equals 1.0
Try block is run.
    i = 2
    No error report and y equals 0.5
Try block is run.
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