Files
hustoj/web/python-docs/tutorial/errors.html
2025-03-09 17:10:56 +08:00

564 lines
52 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_CN">
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>8. 错误和异常 &#8212; Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<script src="../_static/translations.js"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.8.20 文档 中搜索"
href="../_static/opensearch.xml"/>
<link rel="author" title="关于这些文档" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="copyright" title="版权所有" href="../copyright.html" />
<link rel="next" title="9. 类" href="classes.html" />
<link rel="prev" title="7. 输入与输出" href="inputoutput.html" />
<link rel="canonical" href="https://docs.python.org/3/tutorial/errors.html" />
<style>
@media only screen {
table.full-width-table {
width: 100%;
}
}
</style>
<link rel="shortcut icon" type="image/png" href="../_static/py.svg" />
<script type="text/javascript" src="../_static/copybutton.js"></script>
<script type="text/javascript" src="../_static/menu.js"></script>
</head>
<body>
<div class="mobile-nav">
<input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu" />
<label for="menuToggler" class="toggler__label">
<span></span>
</label>
<nav class="nav-content" role="navigation">
<a href="https://www.python.org/" class="nav-logo">
<img src="../_static/py.svg" alt="Logo"/>
</a>
<div class="version_switcher_placeholder"></div>
<form role="search" class="search" action="../search.html" method="get">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
<path fill-rule="nonzero"
d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" fill="#444"></path>
</svg>
<input type="text" name="q" aria-label="快速搜索"/>
<input type="submit" value="转向"/>
</form>
</nav>
<div class="menu-wrapper">
<nav class="menu" role="navigation" aria-label="main navigation">
<div class="language_switcher_placeholder"></div>
<h3><a href="../contents.html">目录</a></h3>
<ul>
<li><a class="reference internal" href="#">8. 错误和异常</a><ul>
<li><a class="reference internal" href="#syntax-errors">8.1. 语法错误</a></li>
<li><a class="reference internal" href="#exceptions">8.2. 异常</a></li>
<li><a class="reference internal" href="#handling-exceptions">8.3. 异常的处理</a></li>
<li><a class="reference internal" href="#raising-exceptions">8.4. 触发异常</a></li>
<li><a class="reference internal" href="#user-defined-exceptions">8.5. 用户自定义异常</a></li>
<li><a class="reference internal" href="#defining-clean-up-actions">8.6. 定义清理操作</a></li>
<li><a class="reference internal" href="#predefined-clean-up-actions">8.7. 预定义的清理操作</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="inputoutput.html"
title="上一章"><span class="section-number">7. </span>输入与输出</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="classes.html"
title="下一章"><span class="section-number">9. </span></a></p>
<div role="note" aria-label="source link">
<h3>本页</h3>
<ul class="this-page-menu">
<li><a href="../bugs.html">报告 Bug</a></li>
<li>
<a href="https://github.com/python/cpython/blob/3.8/Doc/tutorial/errors.rst"
rel="nofollow">显示源代码
</a>
</li>
</ul>
</div>
</nav>
</div>
</div>
<div id="outdated-warning" style="padding: .5em; text-align: center; background-color: #FFBABA; color: #6A0E0E;">
这个文档所针对的是一个已不再受支持的 Python 旧版本。
你应当升级版本,并阅读
<a href="/3/tutorial/errors.html"> Python 当前稳定版本的文档</a>.
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>导航</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="总目录"
accesskey="I">索引</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python 模块索引"
>模块</a> |</li>
<li class="right" >
<a href="classes.html" title="9. 类"
accesskey="N">下一页</a> |</li>
<li class="right" >
<a href="inputoutput.html" title="7. 输入与输出"
accesskey="P">上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 教程</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="errors-and-exceptions">
<span id="tut-errors"></span><h1><span class="section-number">8. </span>错误和异常<a class="headerlink" href="#errors-and-exceptions" title="永久链接至标题"></a></h1>
<p>至此,本教程还未深入介绍错误信息,但如果您尝试过本教程前文中的例子,应该已经看到过一些错误信息。错误可(至少)被分为两种:<em>语法错误</em><em>异常</em></p>
<section id="syntax-errors">
<span id="tut-syntaxerrors"></span><h2><span class="section-number">8.1. </span>语法错误<a class="headerlink" href="#syntax-errors" title="永久链接至标题"></a></h2>
<p>语法错误又称解析错误,是学习 Python 时最常见的错误:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="kc">True</span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Hello world&#39;</span><span class="p">)</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>
<span class="w"> </span><span class="k">while</span> <span class="kc">True</span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Hello world&#39;</span><span class="p">)</span>
<span class="w"> </span><span class="pm">^</span>
<span class="gr">SyntaxError</span>: <span class="n">invalid syntax</span>
</pre></div>
</div>
<p>解析器会复现出现句法错误的代码行,并用小“箭头”指向行里检测到的第一个错误。错误是由箭头 <em>上方</em> 的 token 触发的(至少是在这里检测出的):本例中,在 <a class="reference internal" href="../library/functions.html#print" title="print"><code class="xref py py-func docutils literal notranslate"><span class="pre">print()</span></code></a> 函数中检测到错误,因为,在它前面缺少冒号(<code class="docutils literal notranslate"><span class="pre">':'</span></code> 。错误信息还输出文件名与行号,在使用脚本文件时,就可以知道去哪里查错。</p>
</section>
<section id="exceptions">
<span id="tut-exceptions"></span><h2><span class="section-number">8.2. </span>异常<a class="headerlink" href="#exceptions" title="永久链接至标题"></a></h2>
<p>即使语句或表达式使用了正确的语法,执行时仍可能触发错误。执行时检测到的错误称为 <em>异常</em>,异常不一定导致严重的后果:很快我们就能学会如何处理 Python 的异常。大多数异常不会被程序处理,而是显示下列错误信息:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="mi">10</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">0</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
<span class="gr">ZeroDivisionError</span>: <span class="n">division by zero</span>
<span class="gp">&gt;&gt;&gt; </span><span class="mi">4</span> <span class="o">+</span> <span class="n">spam</span><span class="o">*</span><span class="mi">3</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
<span class="gr">NameError</span>: <span class="n">name &#39;spam&#39; is not defined</span>
<span class="gp">&gt;&gt;&gt; </span><span class="s1">&#39;2&#39;</span> <span class="o">+</span> <span class="mi">2</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
<span class="gr">TypeError</span>: <span class="n">Can&#39;t convert &#39;int&#39; object to str implicitly</span>
</pre></div>
</div>
<p>错误信息的最后一行说明程序遇到了什么类型的错误。异常有不同的类型,而类型名称会作为错误信息的一部分中打印出来:上述示例中的异常类型依次是:<a class="reference internal" href="../library/exceptions.html#ZeroDivisionError" title="ZeroDivisionError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ZeroDivisionError</span></code></a> <a class="reference internal" href="../library/exceptions.html#NameError" title="NameError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">NameError</span></code></a><a class="reference internal" href="../library/exceptions.html#TypeError" title="TypeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">TypeError</span></code></a>。作为异常类型打印的字符串是发生的内置异常的名称。对于所有内置异常都是如此,但对于用户定义的异常则不一定如此(虽然这种规范很有用)。标准的异常类型是内置的标识符(不是保留关键字)。</p>
<p>此行其余部分根据异常类型,结合出错原因,说明错误细节。</p>
<p>错误信息的前一部分以堆栈回溯的形式显示发生异常时的上下文。通常它包含列出源代码行的堆栈回溯;但是它不会显示从标准输入中读取的行。</p>
<p><a class="reference internal" href="../library/exceptions.html#bltin-exceptions"><span class="std std-ref">内置异常</span></a> 列出了内置异常及其含义。</p>
</section>
<section id="handling-exceptions">
<span id="tut-handling"></span><h2><span class="section-number">8.3. </span>异常的处理<a class="headerlink" href="#handling-exceptions" title="永久链接至标题"></a></h2>
<p>可以编写程序处理选定的异常。下例会要求用户一直输入内容,直到输入有效的整数,但允许用户中断程序(使用 <kbd class="kbd docutils literal notranslate">Control-C</kbd> 或操作系统支持的其他操作);注意,用户中断程序会触发 <a class="reference internal" href="../library/exceptions.html#KeyboardInterrupt" title="KeyboardInterrupt"><code class="xref py py-exc docutils literal notranslate"><span class="pre">KeyboardInterrupt</span></code></a> 异常。</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">try</span><span class="p">:</span>
<span class="gp">... </span> <span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">input</span><span class="p">(</span><span class="s2">&quot;Please enter a number: &quot;</span><span class="p">))</span>
<span class="gp">... </span> <span class="k">break</span>
<span class="gp">... </span> <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Oops! That was no valid number. Try again...&quot;</span><span class="p">)</span>
<span class="gp">...</span>
</pre></div>
</div>
<p><a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> 语句的工作原理如下:</p>
<ul class="simple">
<li><p>首先,执行 <em>try 子句</em> <a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a><a class="reference internal" href="../reference/compound_stmts.html#except"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code></a> 关键字之间的(多行)语句)。</p></li>
<li><p>如果没有触发异常,则跳过 <em>except 子句</em><a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> 语句执行完毕。</p></li>
<li><p>如果执行 try 子句时发生了异常,则跳过该子句中剩下的部分。如果异常的类型与 <a class="reference internal" href="../reference/compound_stmts.html#except"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code></a> 关键字后面的异常匹配,则执行 except 子句,然后,继续执行 <a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> 语句之后的代码。</p></li>
<li><p>如果发生的异常不是 except 子句中列示的异常,则将其传递到外部的 <a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> 语句中;如果没有找到处理程序,则它是一个 <em>未处理异常</em>,语句执行将终止,并显示如上所示的消息。</p></li>
</ul>
<p><a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> 语句可以有多个 except 子句,可为不同异常指定相应的处理程序。但最多只会执行一个处理程序。处理程序只处理对应的 try 子句中发生的异常,而不处理同一 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code> 语句内其他处理程序中的异常。except 子句可以用元组命名多个异常,例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="o">...</span> <span class="k">except</span> <span class="p">(</span><span class="ne">RuntimeError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="ne">NameError</span><span class="p">):</span>
<span class="o">...</span> <span class="k">pass</span>
</pre></div>
</div>
<p>发生的异常与 <a class="reference internal" href="../reference/compound_stmts.html#except"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code></a> 子句中的类是同一个类或是它的基类时,异常与 except 子句中的类兼容(反之则不成立 --- 列出派生类的 except 子句与基类不兼容)。例如,下面的代码依次输出 B, C, D</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">B</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">B</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">class</span> <span class="nc">D</span><span class="p">(</span><span class="n">C</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">for</span> <span class="bp">cls</span> <span class="ow">in</span> <span class="p">[</span><span class="n">B</span><span class="p">,</span> <span class="n">C</span><span class="p">,</span> <span class="n">D</span><span class="p">]:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">raise</span> <span class="bp">cls</span><span class="p">()</span>
<span class="k">except</span> <span class="n">D</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;D&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="n">C</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;C&quot;</span><span class="p">)</span>
<span class="k">except</span> <span class="n">B</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;B&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>注意,如果颠倒 except 子句的顺序(把 <code class="docutils literal notranslate"><span class="pre">except</span> <span class="pre">B</span></code> 放到第一个),则输出 BBB --- 即触发第一个匹配的 except 子句。</p>
<p>最后的 except 子句可以省略异常名,以用作通配符。但应谨慎使用,这种方式很容易掩盖真正的编程错误!它还可用于输出错误消息,然后重新触发异常(同样允许调用者处理异常):</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sys</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s1">&#39;myfile.txt&#39;</span><span class="p">)</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
<span class="n">i</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
<span class="k">except</span> <span class="ne">OSError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;OS error: </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">err</span><span class="p">))</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Could not convert data to an integer.&quot;</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Unexpected error:&quot;</span><span class="p">,</span> <span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">()[</span><span class="mi">0</span><span class="p">])</span>
<span class="k">raise</span>
</pre></div>
</div>
<p><a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> ... <a class="reference internal" href="../reference/compound_stmts.html#except"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code></a> 语句支持可选的 <em>else 子句</em>,该子句必须放在所有 except 子句之后。如果 try 子句没有触发异常,但又必须执行一些代码时,这个子句很有用。例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">OSError</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;cannot open&#39;</span><span class="p">,</span> <span class="n">arg</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="s1">&#39;has&#39;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()),</span> <span class="s1">&#39;lines&#39;</span><span class="p">)</span>
<span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
<p>使用 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">else</span></code> 子句比向 <a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> 子句添加额外的代码要好,可以避免意外捕获非 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code> ... <code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code> 语句保护的代码触发的异常。</p>
<p>发生异常时,它可能具有关联值,即异常 <em>参数</em> 。是否需要参数,以及参数的类型取决于异常的类型。</p>
<p>except 子句可以在异常名称后面指定一个变量。这个变量和一个异常实例绑定,它的参数存储在 <code class="docutils literal notranslate"><span class="pre">instance.args</span></code> 中。为了方便起见,异常实例定义了 <a class="reference internal" href="../reference/datamodel.html#object.__str__" title="object.__str__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__str__()</span></code></a> ,因此可以直接打印参数而无需引用 <code class="docutils literal notranslate"><span class="pre">.args</span></code> 。也可以在抛出之前首先实例化异常,并根据需要向其添加任何属性。:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s1">&#39;spam&#39;</span><span class="p">,</span> <span class="s1">&#39;eggs&#39;</span><span class="p">)</span>
<span class="gp">... </span><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">inst</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">inst</span><span class="p">))</span> <span class="c1"># the exception instance</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">inst</span><span class="o">.</span><span class="n">args</span><span class="p">)</span> <span class="c1"># arguments stored in .args</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">inst</span><span class="p">)</span> <span class="c1"># __str__ allows args to be printed directly,</span>
<span class="gp">... </span> <span class="c1"># but may be overridden in exception subclasses</span>
<span class="gp">... </span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">inst</span><span class="o">.</span><span class="n">args</span> <span class="c1"># unpack args</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;x =&#39;</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;y =&#39;</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">&lt;class &#39;Exception&#39;&gt;</span>
<span class="go">(&#39;spam&#39;, &#39;eggs&#39;)</span>
<span class="go">(&#39;spam&#39;, &#39;eggs&#39;)</span>
<span class="go">x = spam</span>
<span class="go">y = eggs</span>
</pre></div>
</div>
<p>如果异常有参数,则它们将作为未处理异常的消息的最后一部分('详细信息')打印。</p>
<p>异常处理程序不仅处理 try 子句中遇到的异常,还处理 try 子句中调用(即使是间接地)的函数内部发生的异常。例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">this_fails</span><span class="p">():</span>
<span class="gp">... </span> <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="o">/</span><span class="mi">0</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span> <span class="n">this_fails</span><span class="p">()</span>
<span class="gp">... </span><span class="k">except</span> <span class="ne">ZeroDivisionError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Handling run-time error:&#39;</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">Handling run-time error: division by zero</span>
</pre></div>
</div>
</section>
<section id="raising-exceptions">
<span id="tut-raising"></span><h2><span class="section-number">8.4. </span>触发异常<a class="headerlink" href="#raising-exceptions" title="永久链接至标题"></a></h2>
<p><a class="reference internal" href="../reference/simple_stmts.html#raise"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">raise</span></code></a> 语句支持强制触发指定的异常。例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">raise</span> <span class="ne">NameError</span><span class="p">(</span><span class="s1">&#39;HiThere&#39;</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
<span class="gr">NameError</span>: <span class="n">HiThere</span>
</pre></div>
</div>
<p><a class="reference internal" href="../reference/simple_stmts.html#raise"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">raise</span></code></a> 唯一的参数就是要触发的异常。这个参数必须是异常实例或异常类(派生自 <a class="reference internal" href="../library/exceptions.html#Exception" title="Exception"><code class="xref py py-class docutils literal notranslate"><span class="pre">Exception</span></code></a> 类)。如果传递的是异常类,将通过调用没有参数的构造函数来隐式实例化:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">raise</span> <span class="ne">ValueError</span> <span class="c1"># shorthand for &#39;raise ValueError()&#39;</span>
</pre></div>
</div>
<p>如果只想判断是否触发了异常,但并不打算处理该异常,则可以使用更简单的 <a class="reference internal" href="../reference/simple_stmts.html#raise"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">raise</span></code></a> 语句重新触发异常:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">raise</span> <span class="ne">NameError</span><span class="p">(</span><span class="s1">&#39;HiThere&#39;</span><span class="p">)</span>
<span class="gp">... </span><span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;An exception flew by!&#39;</span><span class="p">)</span>
<span class="gp">... </span> <span class="k">raise</span>
<span class="gp">...</span>
<span class="go">An exception flew by!</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">2</span>, in <span class="n">&lt;module&gt;</span>
<span class="gr">NameError</span>: <span class="n">HiThere</span>
</pre></div>
</div>
</section>
<section id="user-defined-exceptions">
<span id="tut-userexceptions"></span><h2><span class="section-number">8.5. </span>用户自定义异常<a class="headerlink" href="#user-defined-exceptions" title="永久链接至标题"></a></h2>
<p>程序可以通过创建新的异常类命名自己的异常Python 类的内容详见 <a class="reference internal" href="classes.html#tut-classes"><span class="std std-ref"></span></a>)。不论是以直接还是间接的方式,异常都应从 <a class="reference internal" href="../library/exceptions.html#Exception" title="Exception"><code class="xref py py-exc docutils literal notranslate"><span class="pre">Exception</span></code></a> 类派生。</p>
<p>异常类和其他类一样,可以执行任何操作。但通常会比较简单,只提供让处理异常的程序提取错误信息的一些属性。创建能触发多个不同错误的模块时,一般只为该模块定义异常基类,然后再根据不同的错误条件,创建指定异常类的子类:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Error</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Base class for exceptions in this module.&quot;&quot;&quot;</span>
<span class="k">pass</span>
<span class="k">class</span> <span class="nc">InputError</span><span class="p">(</span><span class="n">Error</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Exception raised for errors in the input.</span>
<span class="sd"> Attributes:</span>
<span class="sd"> expression -- input expression in which the error occurred</span>
<span class="sd"> message -- explanation of the error</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">expression</span> <span class="o">=</span> <span class="n">expression</span>
<span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
<span class="k">class</span> <span class="nc">TransitionError</span><span class="p">(</span><span class="n">Error</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Raised when an operation attempts a state transition that&#39;s not</span>
<span class="sd"> allowed.</span>
<span class="sd"> Attributes:</span>
<span class="sd"> previous -- state at beginning of transition</span>
<span class="sd"> next -- attempted new state</span>
<span class="sd"> message -- explanation of why the specific transition is not allowed</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">previous</span><span class="p">,</span> <span class="nb">next</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">previous</span> <span class="o">=</span> <span class="n">previous</span>
<span class="bp">self</span><span class="o">.</span><span class="n">next</span> <span class="o">=</span> <span class="nb">next</span>
<span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
</pre></div>
</div>
<p>大多数异常命名都以 “Error” 结尾,类似标准异常的命名。</p>
<p>许多标准模块都需要自定义异常,以报告由其定义的函数中出现的错误。有关类的说明,详见 <a class="reference internal" href="classes.html#tut-classes"><span class="std std-ref"></span></a></p>
</section>
<section id="defining-clean-up-actions">
<span id="tut-cleanup"></span><h2><span class="section-number">8.6. </span>定义清理操作<a class="headerlink" href="#defining-clean-up-actions" title="永久链接至标题"></a></h2>
<p><a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> 语句还有一个可选子句,用于定义在所有情况下都必须要执行的清理操作。例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">raise</span> <span class="ne">KeyboardInterrupt</span>
<span class="gp">... </span><span class="k">finally</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Goodbye, world!&#39;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">Goodbye, world!</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">2</span>, in <span class="n">&lt;module&gt;</span>
<span class="nc">KeyboardInterrupt</span>
</pre></div>
</div>
<p>如果存在 <a class="reference internal" href="../reference/compound_stmts.html#finally"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code></a> 子句,则 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code> 子句是 <a class="reference internal" href="../reference/compound_stmts.html#try"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code></a> 语句结束前执行的最后一项任务。不论 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code> 语句是否触发异常,都会执行 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code> 子句。以下内容介绍了几种比较复杂的触发异常情景:</p>
<ul class="simple">
<li><p>如果执行 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code> 子句期间触发了某个异常,则某个 <a class="reference internal" href="../reference/compound_stmts.html#except"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code></a> 子句应处理该异常。如果该异常没有 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code> 子句处理,在 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code> 子句执行后会被重新触发。</p></li>
<li><p><code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code><code class="xref std std-keyword docutils literal notranslate"><span class="pre">else</span></code> 子句执行期间也会触发异常。 同样,该异常会在 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code> 子句执行之后被重新触发。</p></li>
<li><p>如果执行 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code> 语句时遇到 <a class="reference internal" href="../reference/simple_stmts.html#break"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">break</span></code></a>,、<a class="reference internal" href="../reference/simple_stmts.html#continue"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">continue</span></code></a><a class="reference internal" href="../reference/simple_stmts.html#return"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">return</span></code></a> 语句,则 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code> 子句在执行 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">break</span></code><code class="xref std std-keyword docutils literal notranslate"><span class="pre">continue</span></code><code class="xref std std-keyword docutils literal notranslate"><span class="pre">return</span></code> 语句之前执行。</p></li>
<li><p>如果 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code> 子句中包含 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">return</span></code> 语句,则返回值来自 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code> 子句的某个 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">return</span></code> 语句的返回值,而不是来自 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">try</span></code> 子句的 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">return</span></code> 语句的返回值。</p></li>
</ul>
<p>例如:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">bool_return</span><span class="p">():</span>
<span class="gp">... </span> <span class="k">try</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">return</span> <span class="kc">True</span>
<span class="gp">... </span> <span class="k">finally</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">return</span> <span class="kc">False</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">bool_return</span><span class="p">()</span>
<span class="go">False</span>
</pre></div>
</div>
<p>这是一个比较复杂的例子:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">divide</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
<span class="gp">... </span> <span class="k">try</span><span class="p">:</span>
<span class="gp">... </span> <span class="n">result</span> <span class="o">=</span> <span class="n">x</span> <span class="o">/</span> <span class="n">y</span>
<span class="gp">... </span> <span class="k">except</span> <span class="ne">ZeroDivisionError</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;division by zero!&quot;</span><span class="p">)</span>
<span class="gp">... </span> <span class="k">else</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;result is&quot;</span><span class="p">,</span> <span class="n">result</span><span class="p">)</span>
<span class="gp">... </span> <span class="k">finally</span><span class="p">:</span>
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;executing finally clause&quot;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="go">result is 2.0</span>
<span class="go">executing finally clause</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="go">division by zero!</span>
<span class="go">executing finally clause</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="s2">&quot;2&quot;</span><span class="p">,</span> <span class="s2">&quot;1&quot;</span><span class="p">)</span>
<span class="go">executing finally clause</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">3</span>, in <span class="n">divide</span>
<span class="gr">TypeError</span>: <span class="n">unsupported operand type(s) for /: &#39;str&#39; and &#39;str&#39;</span>
</pre></div>
</div>
<p>如上所示,任何情况下都会执行 <a class="reference internal" href="../reference/compound_stmts.html#finally"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code></a> 子句。<a class="reference internal" href="../reference/compound_stmts.html#except"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">except</span></code></a> 子句不处理两个字符串相除触发的 <a class="reference internal" href="../library/exceptions.html#TypeError" title="TypeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">TypeError</span></code></a>,因此会在 <code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code> 子句执行后被重新触发。</p>
<p>在实际应用程序中,<a class="reference internal" href="../reference/compound_stmts.html#finally"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">finally</span></code></a> 子句对于释放外部资源(例如文件或者网络连接)非常有用,无论是否成功使用资源。</p>
</section>
<section id="predefined-clean-up-actions">
<span id="tut-cleanup-with"></span><h2><span class="section-number">8.7. </span>预定义的清理操作<a class="headerlink" href="#predefined-clean-up-actions" title="永久链接至标题"></a></h2>
<p>某些对象定义了不需要该对象时要执行的标准清理操作。无论使用该对象的操作是否成功,都会执行清理操作。比如,下例要打开一个文件,并输出文件内容:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&quot;myfile.txt&quot;</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>这个代码的问题在于,执行完代码后,文件在一段不确定的时间内处于打开状态。在简单脚本中这没有问题,但对于较大的应用程序来说可能会出问题。<a class="reference internal" href="../reference/compound_stmts.html#with"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">with</span></code></a> 语句支持以及时、正确的清理的方式使用文件对象:</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">&quot;myfile.txt&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>语句执行完毕后,即使在处理行时遇到问题,都会关闭文件 <em>f</em>。和文件一样,支持预定义清理操作的对象会在文档中指出这一点。</p>
</section>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h3><a href="../contents.html">目录</a></h3>
<ul>
<li><a class="reference internal" href="#">8. 错误和异常</a><ul>
<li><a class="reference internal" href="#syntax-errors">8.1. 语法错误</a></li>
<li><a class="reference internal" href="#exceptions">8.2. 异常</a></li>
<li><a class="reference internal" href="#handling-exceptions">8.3. 异常的处理</a></li>
<li><a class="reference internal" href="#raising-exceptions">8.4. 触发异常</a></li>
<li><a class="reference internal" href="#user-defined-exceptions">8.5. 用户自定义异常</a></li>
<li><a class="reference internal" href="#defining-clean-up-actions">8.6. 定义清理操作</a></li>
<li><a class="reference internal" href="#predefined-clean-up-actions">8.7. 预定义的清理操作</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="inputoutput.html"
title="上一章"><span class="section-number">7. </span>输入与输出</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="classes.html"
title="下一章"><span class="section-number">9. </span></a></p>
<div role="note" aria-label="source link">
<h3>本页</h3>
<ul class="this-page-menu">
<li><a href="../bugs.html">报告 Bug</a></li>
<li>
<a href="https://github.com/python/cpython/blob/3.8/Doc/tutorial/errors.rst"
rel="nofollow">显示源代码
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>导航</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="总目录"
>索引</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python 模块索引"
>模块</a> |</li>
<li class="right" >
<a href="classes.html" title="9. 类"
>下一页</a> |</li>
<li class="right" >
<a href="inputoutput.html" title="7. 输入与输出"
>上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >Python 教程</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="footer">
&copy; <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
<br />
This page is licensed under the Python Software Foundation License Version 2.
<br />
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
<br />
<br />
The Python Software Foundation is a non-profit corporation.
<a href="https://www.python.org/psf/donations/">Please donate.</a>
<br />
<br />
最后更新于 12月 09, 2024.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
</div>
</body>
</html>