在本教程中,您将在示例的帮助下使用try
,except
和finally
语句学习如何在 Python 程序中处理异常。
Python 异常
Python 有许多内置异常,这些异常在您的程序遇到错误(程序中的某些地方出错)时引发。
当发生这些异常时,Python 解释器将停止当前进程并将其传递给调用进程,直到对其进行处理。 如果不处理,程序将崩溃。
例如,让我们考虑一个程序,其中有一个函数 A
,该函数调用函数B
,该函数又调用函数C
。 如果异常在函数C
中发生,但未在C
中处理,则该异常传递给B
,然后传递给A
。
如果从未处理过,则会显示一条错误消息,并且我们的程序突然突然中止。
在 Python 中捕捉异常
在 Python 中,可以使用try
语句处理异常。
可能引发异常的关键操作放在try
子句中。 处理异常的代码写在except
子句中。
因此,一旦捕获到异常,我们可以选择要执行的操作。 这是一个简单的例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="pl-c"># import module sys to get the type of exception</span> <span class="pl-k">import</span> <span class="pl-s1">sys</span> <span class="pl-s1">randomList</span> <span class="pl-c1">=</span> [<span class="pl-s">'a'</span>, <span class="pl-c1">0</span>, <span class="pl-c1">2</span>] <span class="pl-k">for</span> <span class="pl-s1">entry</span> <span class="pl-c1">in</span> <span class="pl-s1">randomList</span>: <span class="pl-k">try</span>: <span class="pl-en">print</span>(<span class="pl-s">"The entry is"</span>, <span class="pl-s1">entry</span>) <span class="pl-s1">r</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span><span class="pl-c1">/</span><span class="pl-en">int</span>(<span class="pl-s1">entry</span>) <span class="pl-k">break</span> <span class="pl-k">except</span>: <span class="pl-en">print</span>(<span class="pl-s">"Oops!"</span>, <span class="pl-s1">sys</span>.<span class="pl-en">exc_info</span>()[<span class="pl-c1">0</span>], <span class="pl-s">"occurred."</span>) <span class="pl-en">print</span>(<span class="pl-s">"Next entry."</span>) <span class="pl-en">print</span>() <span class="pl-en">print</span>(<span class="pl-s">"The reciprocal of"</span>, <span class="pl-s1">entry</span>, <span class="pl-s">"is"</span>, <span class="pl-s1">r</span>) |
输出
1 2 3 4 5 6 7 8 9 10 |
<span class="pl-v">The</span> <span class="pl-s1">entry</span> <span class="pl-c1">is</span> <span class="pl-s1">a</span> <span class="pl-v">Oops</span>! <span class="pl-c1"><</span><span class="pl-s1">class</span> <span class="pl-s">'ValueError'</span><span class="pl-c1">></span> <span class="pl-s1">occurred</span>. <span class="pl-v">Next</span> <span class="pl-s1">entry</span>. <span class="pl-v">The</span> <span class="pl-s1">entry</span> <span class="pl-c1">is</span> <span class="pl-c1">0</span> <span class="pl-v">Oops</span>! <span class="pl-c1"><</span><span class="pl-s1">class</span> <span class="pl-s">'ZeroDivisionError'</span><span class="pl-c1">></span> <span class="pl-s1">occured</span>. <span class="pl-v">Next</span> <span class="pl-s1">entry</span>. <span class="pl-v">The</span> <span class="pl-s1">entry</span> <span class="pl-c1">is</span> <span class="pl-c1">2</span> <span class="pl-v">The</span> <span class="pl-s1">reciprocal</span> <span class="pl-s1">of</span> <span class="pl-c1">2</span> <span class="pl-c1">is</span> <span class="pl-c1">0.5</span> |
在此程序中,我们遍历randomList
列表的值。 如前所述,可能导致异常的部分位于try
块内。
如果没有异常,则跳过except
块,继续正常流程(最后一个值)。 但是,如果发生任何异常,它将被except
块(第一个和第二个值)捕获。
在这里,我们使用sys
模块内的exc_info()
函数打印异常的名称。 我们可以看到a
导致ValueError
和0
导致ZeroDivisionError
。
由于 Python 中的每个异常都继承自基本Exception
类,因此我们还可以通过以下方式执行上述任务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="pl-c"># import module sys to get the type of exception</span> <span class="pl-k">import</span> <span class="pl-s1">sys</span> <span class="pl-s1">randomList</span> <span class="pl-c1">=</span> [<span class="pl-s">'a'</span>, <span class="pl-c1">0</span>, <span class="pl-c1">2</span>] <span class="pl-k">for</span> <span class="pl-s1">entry</span> <span class="pl-c1">in</span> <span class="pl-s1">randomList</span>: <span class="pl-k">try</span>: <span class="pl-en">print</span>(<span class="pl-s">"The entry is"</span>, <span class="pl-s1">entry</span>) <span class="pl-s1">r</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span><span class="pl-c1">/</span><span class="pl-en">int</span>(<span class="pl-s1">entry</span>) <span class="pl-k">break</span> <span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>: <span class="pl-en">print</span>(<span class="pl-s">"Oops!"</span>, <span class="pl-s1">e</span>.<span class="pl-s1">__class__</span>, <span class="pl-s">"occurred."</span>) <span class="pl-en">print</span>(<span class="pl-s">"Next entry."</span>) <span class="pl-en">print</span>() <span class="pl-en">print</span>(<span class="pl-s">"The reciprocal of"</span>, <span class="pl-s1">entry</span>, <span class="pl-s">"is"</span>, <span class="pl-s1">r</span>) |
该程序具有与上述程序相同的输出。
捕获 Python 中的特定异常
在上面的示例中,我们没有在except
子句中提及任何特定的异常。
这不是一个好的编程习惯,因为它将捕获所有异常并以相同的方式处理每种情况。 我们可以指定except
子句应捕获的异常。
一个try
子句可以具有任意数量的except
子句来处理不同的异常,但是,如果发生异常,则仅执行一个子句。
我们可以使用值的元组在except
子句中指定多个异常。 这是示例伪代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<span class="pl-k">try</span>: <span class="pl-c"># do something</span> <span class="pl-k">pass</span> <span class="pl-k">except</span> <span class="pl-v">ValueError</span>: <span class="pl-c"># handle ValueError exception</span> <span class="pl-k">pass</span> <span class="pl-k">except</span> (<span class="pl-v">TypeError</span>, <span class="pl-v">ZeroDivisionError</span>): <span class="pl-c"># handle multiple exceptions</span> <span class="pl-c"># TypeError and ZeroDivisionError</span> <span class="pl-k">pass</span> <span class="pl-k">except</span>: <span class="pl-c"># handle all other exceptions</span> <span class="pl-k">pass</span> |
在 Python 中引发异常
在 Python 编程中,在运行时发生错误时会引发异常。 我们还可以使用raise
关键字手动引发异常。
我们可以选择将值传递给异常,以阐明引发该异常的原因。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<span class="pl-c1">>></span><span class="pl-c1">></span> <span class="pl-k">raise</span> <span class="pl-v">KeyboardInterrupt</span> <span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>): ... <span class="pl-v">KeyboardInterrupt</span> <span class="pl-c1">>></span><span class="pl-c1">></span> <span class="pl-k">raise</span> <span class="pl-v">MemoryError</span>(<span class="pl-s">"This is an argument"</span>) <span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>): ... <span class="pl-v">MemoryError</span>: <span class="pl-v">This</span> <span class="pl-c1">is</span> <span class="pl-s1">an</span> <span class="pl-s1">argument</span> <span class="pl-c1">>></span><span class="pl-c1">></span> <span class="pl-s1">try</span>: ... <span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-en">int</span>(<span class="pl-en">input</span>(<span class="pl-s">"Enter a positive integer: "</span>)) ... <span class="pl-k">if</span> <span class="pl-s1">a</span> <span class="pl-c1"><=</span> <span class="pl-c1">0</span>: ... <span class="pl-s1">raise</span> <span class="pl-v">ValueError</span>(<span class="pl-s">"That is not a positive number!"</span>) ... <span class="pl-s1">except</span> <span class="pl-v">ValueError</span> <span class="pl-k">as</span> <span class="pl-s1">ve</span>: ... <span class="pl-en">print</span>(<span class="pl-s1">ve</span>) ... <span class="pl-v">Enter</span> <span class="pl-s1">a</span> <span class="pl-s1">positive</span> <span class="pl-s1">integer</span>: <span class="pl-c1">-</span><span class="pl-c1">2</span> <span class="pl-v">That</span> <span class="pl-c1">is</span> <span class="pl-c1">not</span> <span class="pl-s1">a</span> <span class="pl-s1">positive</span> <span class="pl-s1">number</span>! |
Python try-else
子句
在某些情况下,如果try
中的代码块运行无误,则可能要运行某个代码块。 对于这些情况,可以在try
语句中使用可选的else
关键字。
注意:else
子句不会处理else
子句中的异常。
让我们看一个例子:
1 2 3 4 5 6 7 8 9 10 |
<span class="pl-c"># program to print the reciprocal of even numbers</span> <span class="pl-k">try</span>: <span class="pl-s1">num</span> <span class="pl-c1">=</span> <span class="pl-en">int</span>(<span class="pl-en">input</span>(<span class="pl-s">"Enter a number: "</span>)) <span class="pl-k">assert</span> <span class="pl-s1">num</span> <span class="pl-c1">%</span> <span class="pl-c1">2</span> <span class="pl-c1">==</span> <span class="pl-c1">0</span> <span class="pl-k">except</span>: <span class="pl-en">print</span>(<span class="pl-s">"Not an even number!"</span>) <span class="pl-k">else</span>: <span class="pl-s1">reciprocal</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span><span class="pl-c1">/</span><span class="pl-s1">num</span> <span class="pl-en">print</span>(<span class="pl-s1">reciprocal</span>) |
输出:
如果我们传递一个奇数:
1 2 |
<span class="pl-v">Enter</span> <span class="pl-s1">a</span> <span class="pl-s1">number</span>: <span class="pl-c1">1</span> <span class="pl-v">Not</span> <span class="pl-s1">an</span> <span class="pl-s1">even</span> <span class="pl-s1">number</span>! |
如果我们传递一个偶数,则将计算并显示倒数。
1 2 |
<span class="pl-v">Enter</span> <span class="pl-s1">a</span> <span class="pl-s1">number</span>: <span class="pl-c1">4</span> <span class="pl-c1">0.25</span> |
但是,如果传递 0,则会得到ZeroDivisionError
,因为else
内部的代码块未由前面的except
处理。
1 2 3 4 5 |
<span class="pl-v">Enter</span> <span class="pl-s1">a</span> <span class="pl-s1">number</span>: <span class="pl-c1">0</span> <span class="pl-v">Traceback</span> (<span class="pl-s1">most</span> <span class="pl-s1">recent</span> <span class="pl-s1">call</span> <span class="pl-s1">last</span>): <span class="pl-v">File</span> <span class="pl-s">"<string>"</span>, <span class="pl-s1">line</span> <span class="pl-c1">7</span>, <span class="pl-s1">in</span> <span class="pl-c1"><</span><span class="pl-s1">module</span><span class="pl-c1">></span> <span class="pl-s1">reciprocal</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span><span class="pl-c1">/</span><span class="pl-s1">num</span> <span class="pl-v">ZeroDivisionError</span>: <span class="pl-s1">division</span> <span class="pl-s1">by</span> <span class="pl-s1">zero</span> |
Python try-finally
Python 中的try
语句可以具有可选的finally
子句。 该子句无论如何执行,通常用于释放外部资源。
例如,我们可能通过网络或使用文件或图形用户界面(GUI)连接到远程数据中心。
在所有这些情况下,无论程序是否成功运行,我们都必须在程序停止之前清理资源。 这些操作(关闭文件,GUI 或与网络断开连接)在finally
子句中执行,以确保执行。
这是文件操作的示例来说明这一点。
1 2 3 4 5 |
<span class="pl-k">try</span>: <span class="pl-s1">f</span> <span class="pl-c1">=</span> <span class="pl-en">open</span>(<span class="pl-s">"test.txt"</span>,<span class="pl-s1">encoding</span> <span class="pl-c1">=</span> <span class="pl-s">'utf-8'</span>) <span class="pl-c"># perform file operations</span> <span class="pl-k">finally</span>: <span class="pl-s1">f</span>.<span class="pl-en">close</span>() |
这种类型的构造可确保即使在程序执行期间发生异常,也可以关闭文件。