增加python文档
This commit is contained in:
889
web/python-docs/howto/argparse.html
Normal file
889
web/python-docs/howto/argparse.html
Normal file
@@ -0,0 +1,889 @@
|
||||
|
||||
<!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>argparse 教程 — 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="ipaddress模块介绍" href="ipaddress.html" />
|
||||
<link rel="prev" title="如何利用 urllib 包获取网络资源" href="urllib2.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/argparse.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="#">argparse 教程</a><ul>
|
||||
<li><a class="reference internal" href="#concepts">概念</a></li>
|
||||
<li><a class="reference internal" href="#the-basics">基础</a></li>
|
||||
<li><a class="reference internal" href="#introducing-positional-arguments">位置参数介绍</a></li>
|
||||
<li><a class="reference internal" href="#introducing-optional-arguments">可选参数介绍</a><ul>
|
||||
<li><a class="reference internal" href="#short-options">短选项</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#combining-positional-and-optional-arguments">结合位置参数和可选参数</a></li>
|
||||
<li><a class="reference internal" href="#getting-a-little-more-advanced">进行一些小小的改进</a><ul>
|
||||
<li><a class="reference internal" href="#conflicting-options">矛盾的选项</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#conclusion">后记</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="urllib2.html"
|
||||
title="上一章">如何利用 urllib 包获取网络资源</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="ipaddress.html"
|
||||
title="下一章">ipaddress模块介绍</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/howto/argparse.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/howto/argparse.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="ipaddress.html" title="ipaddress模块介绍"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="urllib2.html" title="如何利用 urllib 包获取网络资源"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="argparse-tutorial">
|
||||
<h1>argparse 教程<a class="headerlink" href="#argparse-tutorial" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>Tshepang Lekhonkhobe</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p id="id1">这篇教程旨在作为 <a class="reference internal" href="../library/argparse.html#module-argparse" title="argparse: Command-line option and argument parsing library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">argparse</span></code></a> 的入门介绍,此模块是 Python 标准库中推荐的命令行解析模块。</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p>还有另外两个模块可以完成同样的任务,称为 <a class="reference internal" href="../library/getopt.html#module-getopt" title="getopt: Portable parser for command line options; support both short and long option names."><code class="xref py py-mod docutils literal notranslate"><span class="pre">getopt</span></code></a> (对应于 C 语言中的 <code class="xref c c-func docutils literal notranslate"><span class="pre">getopt()</span></code> 函数) 和被弃用的 <a class="reference internal" href="../library/optparse.html#module-optparse" title="optparse: Command-line option parsing library. (已移除)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">optparse</span></code></a>。还要注意 <a class="reference internal" href="../library/argparse.html#module-argparse" title="argparse: Command-line option and argument parsing library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">argparse</span></code></a> 是基于 <a class="reference internal" href="../library/optparse.html#module-optparse" title="optparse: Command-line option parsing library. (已移除)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">optparse</span></code></a> 的,因此用法与其非常相似。</p>
|
||||
</div>
|
||||
<section id="concepts">
|
||||
<h2>概念<a class="headerlink" href="#concepts" title="永久链接至标题">¶</a></h2>
|
||||
<p>让我们利用 <strong class="command">ls</strong> 命令来展示我们将要在这篇入门教程中探索的功能:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>ls
|
||||
<span class="go">cpython devguide prog.py pypy rm-unused-function.patch</span>
|
||||
<span class="gp">$ </span>ls<span class="w"> </span>pypy
|
||||
<span class="go">ctypes_configure demo dotviewer include lib_pypy lib-python ...</span>
|
||||
<span class="gp">$ </span>ls<span class="w"> </span>-l
|
||||
<span class="go">total 20</span>
|
||||
<span class="go">drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython</span>
|
||||
<span class="go">drwxr-xr-x 4 wena wena 4096 Feb 8 12:04 devguide</span>
|
||||
<span class="go">-rwxr-xr-x 1 wena wena 535 Feb 19 00:05 prog.py</span>
|
||||
<span class="go">drwxr-xr-x 14 wena wena 4096 Feb 7 00:59 pypy</span>
|
||||
<span class="go">-rw-r--r-- 1 wena wena 741 Feb 18 01:01 rm-unused-function.patch</span>
|
||||
<span class="gp">$ </span>ls<span class="w"> </span>--help
|
||||
<span class="go">Usage: ls [OPTION]... [FILE]...</span>
|
||||
<span class="go">List information about the FILEs (the current directory by default).</span>
|
||||
<span class="go">Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.</span>
|
||||
<span class="go">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>我们可以从这四个命令中学到几个概念:</p>
|
||||
<ul class="simple">
|
||||
<li><p><strong class="command">ls</strong> 是一个即使在运行的时候没有提供任何选项,也非常有用的命令。在默认情况下他会输出当前文件夹包含的文件和文件夹。</p></li>
|
||||
<li><p>如果我们想要使用比它默认提供的更多功能,我们需要告诉该命令更多信息。在这个例子里,我们想要查看一个不同的目录,<code class="docutils literal notranslate"><span class="pre">pypy</span></code>。我们所做的是指定所谓的位置参数。之所以这样命名,是因为程序应该如何处理该参数值,完全取决于它在命令行出现的位置。更能体现这个概念的命令如 <strong class="command">cp</strong>,它最基本的用法是 <code class="docutils literal notranslate"><span class="pre">cp</span> <span class="pre">SRC</span> <span class="pre">DEST</span></code>。第一个位置参数指的是*你想要复制的*,第二个位置参数指的是*你想要复制到的位置*。</p></li>
|
||||
<li><p>现在假设我们想要改变这个程序的行为。在我们的例子中,我们不仅仅只是输出每个文件的文件名,还输出了更多信息。在这个例子中,<code class="docutils literal notranslate"><span class="pre">-l</span></code> 被称为可选参数。</p></li>
|
||||
<li><p>这是一段帮助文档的文字。它是非常有用的,因为当你遇到一个你从未使用过的程序时,你可以通过阅读它的帮助文档来弄清楚它是如何运行的。</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="the-basics">
|
||||
<h2>基础<a class="headerlink" href="#the-basics" title="永久链接至标题">¶</a></h2>
|
||||
<p>让我们从一个简单到(几乎)什么也做不了的例子开始:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>以下是该代码的运行结果:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--help
|
||||
<span class="go">usage: prog.py [-h]</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--verbose
|
||||
<span class="go">usage: prog.py [-h]</span>
|
||||
<span class="go">prog.py: error: unrecognized arguments: --verbose</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>foo
|
||||
<span class="go">usage: prog.py [-h]</span>
|
||||
<span class="go">prog.py: error: unrecognized arguments: foo</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>程序运行情况如下:</p>
|
||||
<ul class="simple">
|
||||
<li><p>在没有任何选项的情况下运行脚本不会在标准输出显示任何内容。这没有什么用处。</p></li>
|
||||
<li><p>第二行代码开始展现出 <a class="reference internal" href="../library/argparse.html#module-argparse" title="argparse: Command-line option and argument parsing library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">argparse</span></code></a> 模块的作用。我们几乎什么也没有做,但已经得到一条很好的帮助信息。</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">--help</span></code> 选项,也可缩写为 <code class="docutils literal notranslate"><span class="pre">-h</span></code>,是唯一一个可以直接使用的选项(即不需要指定该选项的内容)。指定任何内容都会导致错误。即便如此,我们也能直接得到一条有用的用法信息。</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="introducing-positional-arguments">
|
||||
<h2>位置参数介绍<a class="headerlink" href="#introducing-positional-arguments" title="永久链接至标题">¶</a></h2>
|
||||
<p>举个例子:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"echo"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">echo</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>运行此程序:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py
|
||||
<span class="go">usage: prog.py [-h] echo</span>
|
||||
<span class="go">prog.py: error: the following arguments are required: echo</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--help
|
||||
<span class="go">usage: prog.py [-h] echo</span>
|
||||
|
||||
<span class="go">positional arguments:</span>
|
||||
<span class="go"> echo</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>foo
|
||||
<span class="go">foo</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>程序运行情况如下:</p>
|
||||
<ul class="simple">
|
||||
<li><p>我们增加了 <code class="xref py py-meth docutils literal notranslate"><span class="pre">add_argument()</span></code> 方法,该方法用于指定程序能够接受哪些命令行选项。在这个例子中,我将选项命名为 <code class="docutils literal notranslate"><span class="pre">echo</span></code>,与其功能一致。</p></li>
|
||||
<li><p>现在调用我们的程序必须要指定一个选项。</p></li>
|
||||
<li><p>The <code class="xref py py-meth docutils literal notranslate"><span class="pre">parse_args()</span></code> method actually returns some data from the
|
||||
options specified, in this case, <code class="docutils literal notranslate"><span class="pre">echo</span></code>.</p></li>
|
||||
<li><p>这一变量是 <a class="reference internal" href="../library/argparse.html#module-argparse" title="argparse: Command-line option and argument parsing library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">argparse</span></code></a> 免费施放的某种 “魔法”(即是说,不需要指定哪个变量是存储哪个值的)。你也可以注意到,这一名称与传递给方法的字符串参数一致,都是 <code class="docutils literal notranslate"><span class="pre">echo</span></code>。</p></li>
|
||||
</ul>
|
||||
<p>然而请注意,尽管显示的帮助看起来清楚完整,但它可以比现在更有帮助。比如我们可以知道 <code class="docutils literal notranslate"><span class="pre">echo</span></code> 是一个位置参数,但我们除了靠猜或者看源代码,没法知道它是用来干什么的。所以,我们可以把它改造得更有用:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"echo"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"echo the string you use here"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">echo</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>然后我们得到:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>-h
|
||||
<span class="go">usage: prog.py [-h] echo</span>
|
||||
|
||||
<span class="go">positional arguments:</span>
|
||||
<span class="go"> echo echo the string you use here</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>现在,来做一些更有用的事情:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"square"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"display a square of a given number"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>以下是该代码的运行结果:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span>
|
||||
<span class="go">Traceback (most recent call last):</span>
|
||||
<span class="go"> File "prog.py", line 5, in <module></span>
|
||||
<span class="go"> print(args.square**2)</span>
|
||||
<span class="go">TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>进展不太顺利。那是因为 <a class="reference internal" href="../library/argparse.html#module-argparse" title="argparse: Command-line option and argument parsing library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">argparse</span></code></a> 会把我们传递给它的选项视作为字符串,除非我们告诉它别这样。所以,让我们来告诉 <a class="reference internal" href="../library/argparse.html#module-argparse" title="argparse: Command-line option and argument parsing library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">argparse</span></code></a> 来把这一输入视为整数:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"square"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"display a square of a given number"</span><span class="p">,</span>
|
||||
<span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>以下是该代码的运行结果:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span>
|
||||
<span class="go">16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>four
|
||||
<span class="go">usage: prog.py [-h] square</span>
|
||||
<span class="go">prog.py: error: argument square: invalid int value: 'four'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>做得不错。当这个程序在收到错误的无效的输入时,它甚至能在执行计算之前先退出,还能显示很有帮助的错误信息。</p>
|
||||
</section>
|
||||
<section id="introducing-optional-arguments">
|
||||
<h2>可选参数介绍<a class="headerlink" href="#introducing-optional-arguments" title="永久链接至标题">¶</a></h2>
|
||||
<p>到目前为止,我们一直在研究位置参数。让我们看看如何添加可选的:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--verbosity"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"verbosity turned on"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>和输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--verbosity<span class="w"> </span><span class="m">1</span>
|
||||
<span class="go">verbosity turned on</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--help
|
||||
<span class="go">usage: prog.py [-h] [--verbosity VERBOSITY]</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> --verbosity VERBOSITY</span>
|
||||
<span class="go"> increase output verbosity</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--verbosity
|
||||
<span class="go">usage: prog.py [-h] [--verbosity VERBOSITY]</span>
|
||||
<span class="go">prog.py: error: argument --verbosity: expected one argument</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>程序运行情况如下:</p>
|
||||
<ul class="simple">
|
||||
<li><p>这一程序被设计为当指定 <code class="docutils literal notranslate"><span class="pre">--verbosity</span></code> 选项时显示某些东西,否则不显示。</p></li>
|
||||
<li><p>不添加这一选项时程序没有提示任何错误而退出,表明这一选项确实是可选的。注意,如果一个可选参数没有被使用时,相关变量被赋值为 <code class="docutils literal notranslate"><span class="pre">None</span></code>,在此例中是 <code class="xref py py-attr docutils literal notranslate"><span class="pre">args.verbosity</span></code>,这也就是为什么它在 <a class="reference internal" href="../reference/compound_stmts.html#if"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">if</span></code></a> 语句中被当作逻辑假。</p></li>
|
||||
<li><p>帮助信息有点不同。</p></li>
|
||||
<li><p>使用 <code class="docutils literal notranslate"><span class="pre">--verbosity</span></code> 选项时,必须指定一个值,但可以是任何值。</p></li>
|
||||
</ul>
|
||||
<p>上述例子接受任何整数值作为 <code class="docutils literal notranslate"><span class="pre">--verbosity</span></code> 的参数,但对于我们的简单程序而言,只有两个值有实际意义:<code class="docutils literal notranslate"><span class="pre">True</span></code> 或者 <code class="docutils literal notranslate"><span class="pre">False</span></code>。让我们据此修改代码:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"--verbose"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">,</span>
|
||||
<span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbose</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"verbosity turned on"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>和输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--verbose
|
||||
<span class="go">verbosity turned on</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--verbose<span class="w"> </span><span class="m">1</span>
|
||||
<span class="go">usage: prog.py [-h] [--verbose]</span>
|
||||
<span class="go">prog.py: error: unrecognized arguments: 1</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--help
|
||||
<span class="go">usage: prog.py [-h] [--verbose]</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> --verbose increase output verbosity</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>程序运行情况如下:</p>
|
||||
<ul class="simple">
|
||||
<li><p>现在,这一选项更多地是一个标志,而非需要接受一个值的什么东西。我们甚至改变了选项的名字来符合这一思路。注意我们现在指定了一个新的关键词 <code class="docutils literal notranslate"><span class="pre">action</span></code>,并赋值为 <code class="docutils literal notranslate"><span class="pre">"store_true"</span></code>。这意味着,当这一选项存在时,为 <code class="xref py py-data docutils literal notranslate"><span class="pre">args.verbose</span></code> 赋值为 <code class="docutils literal notranslate"><span class="pre">True</span></code>。没有指定时则隐含地赋值为 <code class="docutils literal notranslate"><span class="pre">False</span></code>。</p></li>
|
||||
<li><p>当你为其指定一个值时,它会报错,符合作为标志的真正的精神。</p></li>
|
||||
<li><p>留意不同的帮助文字。</p></li>
|
||||
</ul>
|
||||
<section id="short-options">
|
||||
<h3>短选项<a class="headerlink" href="#short-options" title="永久链接至标题">¶</a></h3>
|
||||
<p>如果你熟悉命令行的用法,你会发现我还没讲到这一选项的短版本。这也很简单:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbose"</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">,</span>
|
||||
<span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbose</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"verbosity turned on"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>效果就像这样:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>-v
|
||||
<span class="go">verbosity turned on</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--help
|
||||
<span class="go">usage: prog.py [-h] [-v]</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -v, --verbose increase output verbosity</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>可以注意到,这一新的能力也反映在帮助文本里。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="combining-positional-and-optional-arguments">
|
||||
<h2>结合位置参数和可选参数<a class="headerlink" href="#combining-positional-and-optional-arguments" title="永久链接至标题">¶</a></h2>
|
||||
<p>我们的程序变得越来越复杂了:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"square"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"display a square of a given number"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbose"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="o">**</span><span class="mi">2</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbose</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"the square of </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</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">answer</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>接着是输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py
|
||||
<span class="go">usage: prog.py [-h] [-v] square</span>
|
||||
<span class="go">prog.py: error: the following arguments are required: square</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span>
|
||||
<span class="go">16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>--verbose
|
||||
<span class="go">the square of 4 equals 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--verbose<span class="w"> </span><span class="m">4</span>
|
||||
<span class="go">the square of 4 equals 16</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p>我们带回了一个位置参数,结果发生了报错。</p></li>
|
||||
<li><p>注意顺序无关紧要。</p></li>
|
||||
</ul>
|
||||
<p>给我们的程序加上接受多个冗长度的值,然后实际来用用:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"square"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"display a square of a given number"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbosity"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="o">**</span><span class="mi">2</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"the square of </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</span><span class="p">))</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2">^2 == </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</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">answer</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>和输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span>
|
||||
<span class="go">16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-v
|
||||
<span class="go">usage: prog.py [-h] [-v VERBOSITY] square</span>
|
||||
<span class="go">prog.py: error: argument -v/--verbosity: expected one argument</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-v<span class="w"> </span><span class="m">1</span>
|
||||
<span class="go">4^2 == 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-v<span class="w"> </span><span class="m">2</span>
|
||||
<span class="go">the square of 4 equals 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-v<span class="w"> </span><span class="m">3</span>
|
||||
<span class="go">16</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>除了最后一个,看上去都不错。最后一个暴露了我们的程序中有一个 bug。我们可以通过限制 <code class="docutils literal notranslate"><span class="pre">--verbosity</span></code> 选项可以接受的值来修复它:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"square"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"display a square of a given number"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbosity"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">choices</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="o">**</span><span class="mi">2</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"the square of </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</span><span class="p">))</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2">^2 == </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</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">answer</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>和输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-v<span class="w"> </span><span class="m">3</span>
|
||||
<span class="go">usage: prog.py [-h] [-v {0,1,2}] square</span>
|
||||
<span class="go">prog.py: error: argument -v/--verbosity: invalid choice: 3 (choose from 0, 1, 2)</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-h
|
||||
<span class="go">usage: prog.py [-h] [-v {0,1,2}] square</span>
|
||||
|
||||
<span class="go">positional arguments:</span>
|
||||
<span class="go"> square display a square of a given number</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -v {0,1,2}, --verbosity {0,1,2}</span>
|
||||
<span class="go"> increase output verbosity</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>注意这一改变同时反应在错误信息和帮助信息里。</p>
|
||||
<p>现在,让我们使用另一种的方式来改变冗长度。这种方式更常见,也和 CPython 的可执行文件处理它自己的冗长度参数的方式一致(参考 <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">--help</span></code> 的输出):</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"square"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"display the square of a given number"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbosity"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"count"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="o">**</span><span class="mi">2</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"the square of </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</span><span class="p">))</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2">^2 == </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</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">answer</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>我们引入了另一种动作 <code class="docutils literal notranslate"><span class="pre">count</span></code>,来数某一个可选参数出现了几次:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span>
|
||||
<span class="go">16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-v
|
||||
<span class="go">4^2 == 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-vv
|
||||
<span class="go">the square of 4 equals 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>--verbosity<span class="w"> </span>--verbosity
|
||||
<span class="go">the square of 4 equals 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-v<span class="w"> </span><span class="m">1</span>
|
||||
<span class="go">usage: prog.py [-h] [-v] square</span>
|
||||
<span class="go">prog.py: error: unrecognized arguments: 1</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-h
|
||||
<span class="go">usage: prog.py [-h] [-v] square</span>
|
||||
|
||||
<span class="go">positional arguments:</span>
|
||||
<span class="go"> square display a square of a given number</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -v, --verbosity increase output verbosity</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-vvv
|
||||
<span class="go">16</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p>是的,它现在比前一版本更像是一个标志(和 <code class="docutils literal notranslate"><span class="pre">action="store_true"</span></code> 相似)。这能解释它为什么报错。</p></li>
|
||||
<li><p>它也表现得与 “store_true” 的行为相似。</p></li>
|
||||
<li><p>这给出了一个关于 <code class="docutils literal notranslate"><span class="pre">count</span></code> 动作的效果的演示。你之前很可能应该已经看过这种用法。</p></li>
|
||||
<li><p>如果你不添加 <code class="docutils literal notranslate"><span class="pre">-v</span></code> 标志,这一标志的值会是 <code class="docutils literal notranslate"><span class="pre">None</span></code>。</p></li>
|
||||
<li><p>如期望的那样,添加该标志的长形态能够获得相同的输出。</p></li>
|
||||
<li><p>可惜的是,对于我们的脚本获得的新能力,我们的帮助输出并没有提供很多信息,但我们总是可以通过改善文档来修复这一问题(比如通过 <code class="docutils literal notranslate"><span class="pre">help</span></code> 关键字参数)。</p></li>
|
||||
<li><p>最后一个输出暴露了我们程序中的一个 bug。</p></li>
|
||||
</ul>
|
||||
<p>让我们修复一下:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"square"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"display a square of a given number"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbosity"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"count"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="o">**</span><span class="mi">2</span>
|
||||
|
||||
<span class="c1"># bugfix: replace == with >=</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">>=</span> <span class="mi">2</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"the square of </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</span><span class="p">))</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2">^2 == </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</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">answer</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这是它给我们的输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-vvv
|
||||
<span class="go">the square of 4 equals 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span>-vvvv
|
||||
<span class="go">the square of 4 equals 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span>
|
||||
<span class="go">Traceback (most recent call last):</span>
|
||||
<span class="go"> File "prog.py", line 11, in <module></span>
|
||||
<span class="go"> if args.verbosity >= 2:</span>
|
||||
<span class="go">TypeError: '>=' not supported between instances of 'NoneType' and 'int'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p>第一组输出很好,修复了之前的 bug。也就是说,我们希望任何 >= 2 的值尽可能详尽。</p></li>
|
||||
<li><p>第三组输出并不理想。</p></li>
|
||||
</ul>
|
||||
<p>让我们修复那个 bug:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"square"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"display a square of a given number"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbosity"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"count"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"increase output verbosity"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="o">**</span><span class="mi">2</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">>=</span> <span class="mi">2</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"the square of </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</span><span class="p">))</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2">^2 == </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">square</span><span class="p">,</span> <span class="n">answer</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">answer</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>我们刚刚引入了又一个新的关键字 <code class="docutils literal notranslate"><span class="pre">default</span></code>。我们把它设置为 <code class="docutils literal notranslate"><span class="pre">0</span></code> 来让它可以与其他整数值相互比较。记住,默认情况下如果一个可选参数没有被指定,它的值会是 <code class="docutils literal notranslate"><span class="pre">None</span></code>,并且它不能和整数值相比较(所以产生了 <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>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span>
|
||||
<span class="go">16</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>凭借我们目前已学的东西你就可以做到许多事情,而我们还仅仅学了一些皮毛而已。 <a class="reference internal" href="../library/argparse.html#module-argparse" title="argparse: Command-line option and argument parsing library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">argparse</span></code></a> 模块是非常强大的,在结束篇教程之前我们将再探索更多一些内容。</p>
|
||||
</section>
|
||||
<section id="getting-a-little-more-advanced">
|
||||
<h2>进行一些小小的改进<a class="headerlink" href="#getting-a-little-more-advanced" title="永久链接至标题">¶</a></h2>
|
||||
<p>如果我们想扩展我们的简短程序来执行其他幂次的运算,而不仅是乘方:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"x"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"the base"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"y"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"the exponent"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbosity"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"count"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="o">**</span><span class="n">args</span><span class="o">.</span><span class="n">y</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">>=</span> <span class="mi">2</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2"> to the power </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">answer</span><span class="p">))</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2">^</span><span class="si">{}</span><span class="s2"> == </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">answer</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">answer</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py
|
||||
<span class="go">usage: prog.py [-h] [-v] x y</span>
|
||||
<span class="go">prog.py: error: the following arguments are required: x, y</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>-h
|
||||
<span class="go">usage: prog.py [-h] [-v] x y</span>
|
||||
|
||||
<span class="go">positional arguments:</span>
|
||||
<span class="go"> x the base</span>
|
||||
<span class="go"> y the exponent</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -v, --verbosity</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>-v
|
||||
<span class="go">4^2 == 16</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>请注意到目前为止我们一直在使用详细级别来 <em>更改</em> 所显示的文本。 以下示例则使用详细级别来显示 <em>更多的</em> 文本:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"x"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"the base"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"y"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"the exponent"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbosity"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"count"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="o">**</span><span class="n">args</span><span class="o">.</span><span class="n">y</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">>=</span> <span class="mi">2</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Running '</span><span class="si">{}</span><span class="s2">'"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="vm">__file__</span><span class="p">))</span>
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">verbosity</span> <span class="o">>=</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2">^</span><span class="si">{}</span><span class="s2"> == "</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">y</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">answer</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span>
|
||||
<span class="go">16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>-v
|
||||
<span class="go">4^2 == 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>-vv
|
||||
<span class="go">Running 'prog.py'</span>
|
||||
<span class="go">4^2 == 16</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="conflicting-options">
|
||||
<h3>矛盾的选项<a class="headerlink" href="#conflicting-options" title="永久链接至标题">¶</a></h3>
|
||||
<p>到目前为止,我们一直在使用 <a class="reference internal" href="../library/argparse.html#argparse.ArgumentParser" title="argparse.ArgumentParser"><code class="xref py py-class docutils literal notranslate"><span class="pre">argparse.ArgumentParser</span></code></a> 实例的两个方法。 让我们再介绍第三个方法 <code class="xref py py-meth docutils literal notranslate"><span class="pre">add_mutually_exclusive_group()</span></code>。 它允许我们指定彼此相互冲突的选项。 让我们再更改程序的其余部分以便使用新功能更有意义:我们将引入 <code class="docutils literal notranslate"><span class="pre">--quiet</span></code> 选项,它将与 <code class="docutils literal notranslate"><span class="pre">--verbose</span></code> 正好相反:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
|
||||
<span class="n">group</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_mutually_exclusive_group</span><span class="p">()</span>
|
||||
<span class="n">group</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbose"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">)</span>
|
||||
<span class="n">group</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-q"</span><span class="p">,</span> <span class="s2">"--quiet"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"x"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"the base"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"y"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"the exponent"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="o">**</span><span class="n">args</span><span class="o">.</span><span class="n">y</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">quiet</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">answer</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">verbose</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2"> to the power </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">answer</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="s2">"</span><span class="si">{}</span><span class="s2">^</span><span class="si">{}</span><span class="s2"> == </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">answer</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>我们的程序现在变得更简洁了,我们出于演示需要略去了一些功能。 无论如何,输出是这样的:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span>
|
||||
<span class="go">4^2 == 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>-q
|
||||
<span class="go">16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>-v
|
||||
<span class="go">4 to the power 2 equals 16</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>-vq
|
||||
<span class="go">usage: prog.py [-h] [-v | -q] x y</span>
|
||||
<span class="go">prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose</span>
|
||||
<span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">2</span><span class="w"> </span>-v<span class="w"> </span>--quiet
|
||||
<span class="go">usage: prog.py [-h] [-v | -q] x y</span>
|
||||
<span class="go">prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这应该很容易理解。 我添加了末尾的输出这样你就可以看到其所达到的灵活性,即混合使用长和短两种形式的选项。</p>
|
||||
<p>在我们收尾之前,你也许希望告诉你的用户这个程序的主要目标,以免他们还不清楚:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">argparse</span>
|
||||
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"calculate X to the power of Y"</span><span class="p">)</span>
|
||||
<span class="n">group</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_mutually_exclusive_group</span><span class="p">()</span>
|
||||
<span class="n">group</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-v"</span><span class="p">,</span> <span class="s2">"--verbose"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">)</span>
|
||||
<span class="n">group</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"-q"</span><span class="p">,</span> <span class="s2">"--quiet"</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"x"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"the base"</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s2">"y"</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">"the exponent"</span><span class="p">)</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
<span class="n">answer</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="o">**</span><span class="n">args</span><span class="o">.</span><span class="n">y</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">quiet</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">answer</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">args</span><span class="o">.</span><span class="n">verbose</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2"> to the power </span><span class="si">{}</span><span class="s2"> equals </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">answer</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="s2">"</span><span class="si">{}</span><span class="s2">^</span><span class="si">{}</span><span class="s2"> == </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">answer</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>请注意用法文本中有细微的差异。 注意 <code class="docutils literal notranslate"><span class="pre">[-v</span> <span class="pre">|</span> <span class="pre">-q]</span></code>,它的意思是说我们可以使用 <code class="docutils literal notranslate"><span class="pre">-v</span></code> 或 <code class="docutils literal notranslate"><span class="pre">-q</span></code>,但不能同时使用两者:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>prog.py<span class="w"> </span>--help
|
||||
<span class="go">usage: prog.py [-h] [-v | -q] x y</span>
|
||||
|
||||
<span class="go">calculate X to the power of Y</span>
|
||||
|
||||
<span class="go">positional arguments:</span>
|
||||
<span class="go"> x the base</span>
|
||||
<span class="go"> y the exponent</span>
|
||||
|
||||
<span class="go">optional arguments:</span>
|
||||
<span class="go"> -h, --help show this help message and exit</span>
|
||||
<span class="go"> -v, --verbose</span>
|
||||
<span class="go"> -q, --quiet</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="conclusion">
|
||||
<h2>后记<a class="headerlink" href="#conclusion" title="永久链接至标题">¶</a></h2>
|
||||
<p>除了这里显示的内容,<a class="reference internal" href="../library/argparse.html#module-argparse" title="argparse: Command-line option and argument parsing library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">argparse</span></code></a> 模块还提供了更多功能。 它的文档相当详细和完整,包含大量示例。 完成这个教程之后,你应该能毫不困难地阅读该文档。</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="#">argparse 教程</a><ul>
|
||||
<li><a class="reference internal" href="#concepts">概念</a></li>
|
||||
<li><a class="reference internal" href="#the-basics">基础</a></li>
|
||||
<li><a class="reference internal" href="#introducing-positional-arguments">位置参数介绍</a></li>
|
||||
<li><a class="reference internal" href="#introducing-optional-arguments">可选参数介绍</a><ul>
|
||||
<li><a class="reference internal" href="#short-options">短选项</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#combining-positional-and-optional-arguments">结合位置参数和可选参数</a></li>
|
||||
<li><a class="reference internal" href="#getting-a-little-more-advanced">进行一些小小的改进</a><ul>
|
||||
<li><a class="reference internal" href="#conflicting-options">矛盾的选项</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#conclusion">后记</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="urllib2.html"
|
||||
title="上一章">如何利用 urllib 包获取网络资源</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="ipaddress.html"
|
||||
title="下一章">ipaddress模块介绍</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/howto/argparse.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="ipaddress.html" title="ipaddress模块介绍"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="urllib2.html" title="如何利用 urllib 包获取网络资源"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
1341
web/python-docs/howto/clinic.html
Normal file
1341
web/python-docs/howto/clinic.html
Normal file
File diff suppressed because it is too large
Load Diff
258
web/python-docs/howto/cporting.html
Normal file
258
web/python-docs/howto/cporting.html
Normal file
@@ -0,0 +1,258 @@
|
||||
|
||||
<!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>将扩展模块移植到 Python 3 — 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="用 Python 进行 Curses 编程" href="curses.html" />
|
||||
<link rel="prev" title="将 Python 2 代码迁移到 Python 3" href="pyporting.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/cporting.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>
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="pyporting.html"
|
||||
title="上一章">将 Python 2 代码迁移到 Python 3</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="curses.html"
|
||||
title="下一章">用 Python 进行 Curses 编程</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/howto/cporting.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/howto/cporting.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="curses.html" title="用 Python 进行 Curses 编程"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="pyporting.html" title="将 Python 2 代码迁移到 Python 3"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="porting-extension-modules-to-python-3">
|
||||
<span id="cporting-howto"></span><h1>将扩展模块移植到 Python 3<a class="headerlink" href="#porting-extension-modules-to-python-3" title="永久链接至标题">¶</a></h1>
|
||||
<p>对于将扩展模块移植到 Python 3,我们推荐下列资源:</p>
|
||||
<ul class="simple">
|
||||
<li><p><em>Supporting Python 3: An in-depth guide</em> 中的 <a class="reference external" href="http://python3porting.com/cextensions.html">Migrating C extensions</a> 这一章,这本书介绍了如何从 Python 2 迁移到 Python 3,包括指导读者如何移植扩展模块。</p></li>
|
||||
<li><p><em>py3c</em> 项目中的 <a class="reference external" href="https://py3c.readthedocs.io/en/latest/guide.html">Porting guide</a> 提供了有关支持代码的指导性建议。</p></li>
|
||||
<li><p><a class="reference external" href="http://cython.org/">Cython</a> 和 <a class="reference external" href="https://cffi.readthedocs.io/en/latest/">CFFI</a> 库提供了对于 Python 的 C API 的抽象。 扩展大都需要进行重写以使用两者中的一个,然后就可以通过库来处理各种 Python 版本和实现之间的差异。</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="pyporting.html"
|
||||
title="上一章">将 Python 2 代码迁移到 Python 3</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="curses.html"
|
||||
title="下一章">用 Python 进行 Curses 编程</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/howto/cporting.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="curses.html" title="用 Python 进行 Curses 编程"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="pyporting.html" title="将 Python 2 代码迁移到 Python 3"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
564
web/python-docs/howto/curses.html
Normal file
564
web/python-docs/howto/curses.html
Normal file
@@ -0,0 +1,564 @@
|
||||
|
||||
<!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>用 Python 进行 Curses 编程 — 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="描述器使用指南" href="descriptor.html" />
|
||||
<link rel="prev" title="将扩展模块移植到 Python 3" href="cporting.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/curses.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="#">用 Python 进行 Curses 编程</a><ul>
|
||||
<li><a class="reference internal" href="#what-is-curses">curses 是什么?</a><ul>
|
||||
<li><a class="reference internal" href="#the-python-curses-module">Python 的 curses 模块</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#starting-and-ending-a-curses-application">开始和结束curses应用程序</a></li>
|
||||
<li><a class="reference internal" href="#windows-and-pads">窗口和面板</a></li>
|
||||
<li><a class="reference internal" href="#displaying-text">显示文字</a><ul>
|
||||
<li><a class="reference internal" href="#attributes-and-color">属性和颜色</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#user-input">用户输入</a></li>
|
||||
<li><a class="reference internal" href="#for-more-information">更多的信息</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="cporting.html"
|
||||
title="上一章">将扩展模块移植到 Python 3</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="descriptor.html"
|
||||
title="下一章">描述器使用指南</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/howto/curses.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/howto/curses.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="descriptor.html" title="描述器使用指南"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="cporting.html" title="将扩展模块移植到 Python 3"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="curses-programming-with-python">
|
||||
<span id="curses-howto"></span><h1>用 Python 进行 Curses 编程<a class="headerlink" href="#curses-programming-with-python" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>A.M. Kuchling, Eric S. Raymond</p>
|
||||
</dd>
|
||||
<dt class="field-even">发布版本</dt>
|
||||
<dd class="field-even"><p>2.04</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="topic">
|
||||
<p class="topic-title">摘要</p>
|
||||
<p>本文档介绍了如何使用 <a class="reference internal" href="../library/curses.html#module-curses" title="curses: An interface to the curses library, providing portable terminal handling. (Unix)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">curses</span></code></a> 扩展模块控制文本模式的显示。</p>
|
||||
</div>
|
||||
<section id="what-is-curses">
|
||||
<h2>curses 是什么?<a class="headerlink" href="#what-is-curses" title="永久链接至标题">¶</a></h2>
|
||||
<p>curses 库为基于文本的终端提供了独立于终端的屏幕绘制和键盘处理功能;这些终端包括 VT100,Linux 控制台以及各种程序提供的模拟终端。显示终端支持各种控制代码以执行常见的操作,例如移动光标,滚动屏幕和擦除区域。不同的终端使用相差很大的代码,并且往往有自己的小怪癖。</p>
|
||||
<p>在普遍使用图形显示的世界中,人们可能会问“为什么自找要麻烦”?毕竟字符单元显示终端确实是一种过时的技术,但是在某些领域中,能够用它们做花哨的事情仍然很有价值。一个小众市场是在不运行 X server 的小型或嵌入式 Unix 上。另一个是在提供图形支持之前,可能需要运行的工具,例如操作系统安装程序和内核配置程序。</p>
|
||||
<p>curses 库提供了相当基础的功能,为程序员提供了包含多个非重叠文本窗口的显示的抽象。窗口的内容可以通过多种方式更改---添加文本,擦除文本,更改其外观---以及curses库将确定需要向终端发送哪些控制代码以产生正确的输出。 curses并没有提供诸多用户界面概念,例如按钮,复选框或对话框。如果需要这些功能,请考虑用户界面库,例如 <a class="reference external" href="https://pypi.org/project/urwid/">Urwid</a> 。</p>
|
||||
<p>curses 库最初是为BSD Unix 编写的。 后来 AT&T 的Unix System V 版本加入了许多增强功能和新功能。如今BSD curses已不再维护,被ncurses取代,ncurses是 AT&T 接口的开源实现。如果使用的是 Linux 或 FreeBSD 等开源Unix系统,则几乎肯定会使用ncurses。由于大多数当前的商业Unix版本都基于System V代码,因此这里描述的所有功能可能都可用。但是,某些专有Unix所带来的较早版本的curses可能无法支持所有功能。</p>
|
||||
<p>Windows 版本的 Python 不包含 <a class="reference internal" href="../library/curses.html#module-curses" title="curses: An interface to the curses library, providing portable terminal handling. (Unix)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">curses</span></code></a> 模块。提供了一个名为 <a class="reference external" href="https://pypi.org/project/UniCurses">UniCurses</a> 的移植版本。也可以尝试使用 Fredrik Lundh 编写 <a class="reference external" href="http://effbot.org/zone/console-index.htm">the Console module</a>,它使用了与curses不相同的API,但提供了可光标定位的文本输出,完全支持鼠标和键盘输入。</p>
|
||||
<section id="the-python-curses-module">
|
||||
<h3>Python 的 curses 模块<a class="headerlink" href="#the-python-curses-module" title="永久链接至标题">¶</a></h3>
|
||||
<p>此 Python 模块相当简单地封装了 curses 提供的 C 函数;如果你已经熟悉在 C 语言中使用 curses 编程,把这些知识转移的 Python 是非常容易的。最大的差异在于 Python 中的接口通过把不同的 C 函数合并来让事情变得更简单,比如 <code class="xref c c-func docutils literal notranslate"><span class="pre">addstr()</span></code>、<code class="xref c c-func docutils literal notranslate"><span class="pre">mvaddstr()</span></code> 和 <code class="xref c c-func docutils literal notranslate"><span class="pre">mvwaddstr()</span></code> 三个 C 函数被并入 <a class="reference internal" href="../library/curses.html#curses.window.addstr" title="curses.window.addstr"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addstr()</span></code></a> 这一个方法。下文中会描述更多的细节。</p>
|
||||
<p>本 HOWTO 是关于使用 curses 和 Python 编写文本模式程序的概述。它并不被设计为一个 curses API 的完整指南;如需完整指南,请参见 ncurses 的 Python 库指南章节和 ncurses 的 C 手册页。相对地,本 HOWTO 将会给你一些基本思路。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="starting-and-ending-a-curses-application">
|
||||
<h2>开始和结束curses应用程序<a class="headerlink" href="#starting-and-ending-a-curses-application" title="永久链接至标题">¶</a></h2>
|
||||
<p>在做任何事情之前,curses 必须先被初始化。可以通过调用函数 <a class="reference internal" href="../library/curses.html#curses.initscr" title="curses.initscr"><code class="xref py py-func docutils literal notranslate"><span class="pre">initscr()</span></code></a> 来实现,它将查明终端的类型,向终端发送任何必须的设置代码,并创建多种内部数据结构。如果此操作成功,<code class="xref py py-func docutils literal notranslate"><span class="pre">initscr()</span></code> 将会返回一个代表整个屏幕的窗口对象;它通常会遵循对应的 C 变量名被称作 <code class="docutils literal notranslate"><span class="pre">stdscr</span></code>:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">curses</span>
|
||||
<span class="n">stdscr</span> <span class="o">=</span> <span class="n">curses</span><span class="o">.</span><span class="n">initscr</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>使用 curses 的应用程序通常会关闭按键自动上屏,目的是读取按键并只在特定情况下展示它们。这需要调用函数 <a class="reference internal" href="../library/curses.html#curses.noecho" title="curses.noecho"><code class="xref py py-func docutils literal notranslate"><span class="pre">noecho()</span></code></a>:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">curses</span><span class="o">.</span><span class="n">noecho</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>应用程序也会广泛地需要立即响应按键,而不需要按下回车键;这被称为 “cbreak” 模式,与通常的缓冲输入模式相对:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">curses</span><span class="o">.</span><span class="n">cbreak</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>终端通常会以多字节转义序列的形式返回特殊按键,比如光标键和导航键比如 Page Up 键和 Home 键。尽管你可以编写你的程序来应对这些序列,curses 能够代替你做到这件事,返回一个特殊值比如 <code class="xref py py-const docutils literal notranslate"><span class="pre">curses.KEY_LEFT</span></code>。为了让 curses 做这项工作,你需要启用 keypad 模式:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">stdscr</span><span class="o">.</span><span class="n">keypad</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>终止一个 curses 应用程序比建立一个容易得多,你只需要调用:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">curses</span><span class="o">.</span><span class="n">nocbreak</span><span class="p">()</span>
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">keypad</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">curses</span><span class="o">.</span><span class="n">echo</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>来还原对终端作出的 curses 友好设置。然后,调用函数 <a class="reference internal" href="../library/curses.html#curses.endwin" title="curses.endwin"><code class="xref py py-func docutils literal notranslate"><span class="pre">endwin()</span></code></a> 来将终端还原到它的原始操作模式:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">curses</span><span class="o">.</span><span class="n">endwin</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>调试一个 curses 应用程序时常会发生,一个应用程序还未能还原终端到原本的状态就意外退出了,这会搅乱你的终端。在 Python 中这常常会发生在你的代码中有 bug 并引发了一个未捕获的异常。当你尝试输入时按键不会上屏,这使得使用终端变得困难。</p>
|
||||
<p>在 Python 中你可以避免这些复杂问题并让调试变得更简单,只需要导入 <a class="reference internal" href="../library/curses.html#curses.wrapper" title="curses.wrapper"><code class="xref py py-func docutils literal notranslate"><span class="pre">curses.wrapper()</span></code></a> 函数并像这样使用它:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">curses</span> <span class="kn">import</span> <span class="n">wrapper</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">stdscr</span><span class="p">):</span>
|
||||
<span class="c1"># Clear screen</span>
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># This raises ZeroDivisionError when i == 10.</span>
|
||||
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">11</span><span class="p">):</span>
|
||||
<span class="n">v</span> <span class="o">=</span> <span class="n">i</span><span class="o">-</span><span class="mi">10</span>
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">addstr</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'10 divided by </span><span class="si">{}</span><span class="s1"> is </span><span class="si">{}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="mi">10</span><span class="o">/</span><span class="n">v</span><span class="p">))</span>
|
||||
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">refresh</span><span class="p">()</span>
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">getkey</span><span class="p">()</span>
|
||||
|
||||
<span class="n">wrapper</span><span class="p">(</span><span class="n">main</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>函数 <a class="reference internal" href="../library/curses.html#curses.wrapper" title="curses.wrapper"><code class="xref py py-func docutils literal notranslate"><span class="pre">wrapper()</span></code></a> 接受一个可调用对象并首先进行上述初始化过程,在终端支持着色时还会初始化颜色。接着 <code class="xref py py-func docutils literal notranslate"><span class="pre">wrapper()</span></code> 运行你提供的可调用对象。当该可调用对象返回时,<code class="xref py py-func docutils literal notranslate"><span class="pre">wrapper()</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>...<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>
|
||||
</section>
|
||||
<section id="windows-and-pads">
|
||||
<h2>窗口和面板<a class="headerlink" href="#windows-and-pads" title="永久链接至标题">¶</a></h2>
|
||||
<p>窗口是 curses 中的基本抽象。一个窗口对象表示了屏幕上的一个矩形区域,并且提供方法来显示文本、擦除文本、允许用户输入字符串等等。</p>
|
||||
<p>函数 <a class="reference internal" href="../library/curses.html#curses.initscr" title="curses.initscr"><code class="xref py py-func docutils literal notranslate"><span class="pre">initscr()</span></code></a> 返回的 <code class="docutils literal notranslate"><span class="pre">stdscr</span></code> 对象覆盖整个屏幕。许多程序可能只需要这一个窗口,但你可能希望把屏幕分割为多个更小的窗口,来分别重绘或者清除它们。函数 <a class="reference internal" href="../library/curses.html#curses.newwin" title="curses.newwin"><code class="xref py py-func docutils literal notranslate"><span class="pre">newwin()</span></code></a> 根据给定的尺寸创建一个新窗口,并返回这个新的窗口对象:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">begin_x</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span> <span class="n">begin_y</span> <span class="o">=</span> <span class="mi">7</span>
|
||||
<span class="n">height</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span> <span class="n">width</span> <span class="o">=</span> <span class="mi">40</span>
|
||||
<span class="n">win</span> <span class="o">=</span> <span class="n">curses</span><span class="o">.</span><span class="n">newwin</span><span class="p">(</span><span class="n">height</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">begin_y</span><span class="p">,</span> <span class="n">begin_x</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>注意 curses 使用的坐标系统与寻常的不同。坐标始终是以 <em>y,x</em> 的顺序传递,并且左上角是坐标 (0,0)。这打破了正常的坐标处理约定,即 <em>x</em> 坐标在前。这是一个与其他计算机应用程序糟糕的差异,但这从 curses 最初被编写出来就已是它的一部分,现在想要修改它已为时已晚。</p>
|
||||
<p>你的应用程序能够查明屏幕的尺寸,<code class="xref py py-data docutils literal notranslate"><span class="pre">curses.LINES</span></code> 和 <code class="xref py py-data docutils literal notranslate"><span class="pre">curses.COLS</span></code> 分别代表了 <em>y</em> 和 <em>x</em> 方向上的尺寸。合理的坐标应位于 <code class="docutils literal notranslate"><span class="pre">(0,0)</span></code> 到 <code class="docutils literal notranslate"><span class="pre">(curses.LINES</span> <span class="pre">-</span> <span class="pre">1,</span> <span class="pre">curses.COLS</span> <span class="pre">-</span> <span class="pre">1)</span></code> 范围内。</p>
|
||||
<p>当你调用一个方法来显示或擦除文本时,效果并不会立即显示。相反,你必须调用窗口对象的 <a class="reference internal" href="../library/curses.html#curses.window.refresh" title="curses.window.refresh"><code class="xref py py-meth docutils literal notranslate"><span class="pre">refresh()</span></code></a> 方法来更新屏幕。</p>
|
||||
<p>这是因为 curses 最初是为 300 波特的龟速终端连接编写的;在这些终端上,压制重绘屏幕的时间就非常重要。相对地,当你调用 <code class="xref py py-meth docutils literal notranslate"><span class="pre">refresh()</span></code> 时,curses 会累积屏幕的修改并以效率最高的方式显示它们。打个比方,如果你的程序在一个窗口内显示一些文本然后清楚了这个窗口,那么这些原始文本不需要被发送,因为它们甚至不曾能被看见。</p>
|
||||
<p>在实践中,显式地告诉 curses 来重绘一个窗口并不会太复杂化 curses 编程。大部分程序会显示一堆内容然后等待按键或者其他某些用户侧动作。你要做的事情就是,保证屏幕在暂停并等待用户输入前被重绘,只需要先调用 <code class="docutils literal notranslate"><span class="pre">stdscr.refresh()</span></code> 或者其他相关窗口的 <code class="xref py py-meth docutils literal notranslate"><span class="pre">refresh()</span></code> 方法。</p>
|
||||
<p>一个面板是一种特殊的窗口,它可以比实际的显示屏幕更大,并且能只显示它的一部分。创建面板需要指定面板的高度和宽度,但刷新一个面板需要给出屏幕坐标和面板的需要显示的局部。</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">pad</span> <span class="o">=</span> <span class="n">curses</span><span class="o">.</span><span class="n">newpad</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
|
||||
<span class="c1"># These loops fill the pad with letters; addch() is</span>
|
||||
<span class="c1"># explained in the next section</span>
|
||||
<span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">99</span><span class="p">):</span>
|
||||
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">99</span><span class="p">):</span>
|
||||
<span class="n">pad</span><span class="o">.</span><span class="n">addch</span><span class="p">(</span><span class="n">y</span><span class="p">,</span><span class="n">x</span><span class="p">,</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">'a'</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="n">x</span><span class="o">+</span><span class="n">y</span><span class="o">*</span><span class="n">y</span><span class="p">)</span> <span class="o">%</span> <span class="mi">26</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Displays a section of the pad in the middle of the screen.</span>
|
||||
<span class="c1"># (0,0) : coordinate of upper-left corner of pad area to display.</span>
|
||||
<span class="c1"># (5,5) : coordinate of upper-left corner of window area to be filled</span>
|
||||
<span class="c1"># with pad content.</span>
|
||||
<span class="c1"># (20, 75) : coordinate of lower-right corner of window area to be</span>
|
||||
<span class="c1"># : filled with pad content.</span>
|
||||
<span class="n">pad</span><span class="o">.</span><span class="n">refresh</span><span class="p">(</span> <span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span><span class="mi">75</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>此 <code class="xref py py-meth docutils literal notranslate"><span class="pre">refresh()</span></code> 调用会在屏幕坐标 (5,5) 到坐标 (20,75) 的矩形范围内显示面板的一个部分,被显示的部分在面板上的坐标是 (0,0)。除了上述差异,面板与常规的窗口相同,也支持相同的方法。</p>
|
||||
<p>如果你在屏幕上有多个窗口和面板,有一个更有效率的方法来更新窗口,避免每个部分单独更新时烦人的屏幕闪烁。<code class="xref py py-meth docutils literal notranslate"><span class="pre">refresh()</span></code> 实际上做了两件事:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>调用每个窗口的 <a class="reference internal" href="../library/curses.html#curses.window.noutrefresh" title="curses.window.noutrefresh"><code class="xref py py-meth docutils literal notranslate"><span class="pre">noutrefresh()</span></code></a> 方法来更新一个表达屏幕期望状态的底层的数据结构。</p></li>
|
||||
<li><p>调用函数 <a class="reference internal" href="../library/curses.html#curses.doupdate" title="curses.doupdate"><code class="xref py py-func docutils literal notranslate"><span class="pre">doupdate()</span></code></a> 来改变物理屏幕来符合这个数据结构中记录的期望状态。</p></li>
|
||||
</ol>
|
||||
<p>你可以改为调用在多个窗口上 <code class="xref py py-meth docutils literal notranslate"><span class="pre">noutrefresh()</span></code> 方法来更新该数据结构,然后调用函数 <code class="xref py py-func docutils literal notranslate"><span class="pre">doupdate()</span></code> 来更新屏幕。</p>
|
||||
</section>
|
||||
<section id="displaying-text">
|
||||
<h2>显示文字<a class="headerlink" href="#displaying-text" title="永久链接至标题">¶</a></h2>
|
||||
<p>从一名 C 语言程序员的视角来看,curses 有时看起来就像是一堆略有差异的函数组成的扭曲迷宫。举个例子,<code class="xref c c-func docutils literal notranslate"><span class="pre">addstr()</span></code> 在 <code class="docutils literal notranslate"><span class="pre">stdscr</span></code> 窗口的当前光标位置显示一个字符串,而 <code class="xref c c-func docutils literal notranslate"><span class="pre">mvaddstr()</span></code> 则是先移动到一个给定的 y,x 坐标再显示字符串。<code class="xref c c-func docutils literal notranslate"><span class="pre">waddstr()</span></code> 与 <code class="xref c c-func docutils literal notranslate"><span class="pre">addstr()</span></code> 类似,但允许指定一个窗口而非默认的 <code class="docutils literal notranslate"><span class="pre">stdscr</span></code>。<code class="xref c c-func docutils literal notranslate"><span class="pre">mvwaddstr()</span></code> 允许同时指定一个窗口和一个坐标。</p>
|
||||
<p>幸运的是,Python 接口隐藏了所有这些细节。<code class="docutils literal notranslate"><span class="pre">stdscr</span></code> 和其他任何窗口一样是一个窗口对象,并且诸如 <a class="reference internal" href="../library/curses.html#curses.window.addstr" title="curses.window.addstr"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addstr()</span></code></a> 之类的方法接受多种参数形式。通常有四种形式。</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 41%" />
|
||||
<col style="width: 59%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>形式</p></th>
|
||||
<th class="head"><p>描述</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p><em>str</em> 或 <em>ch</em></p></td>
|
||||
<td><p>在当前位置显示字符串 <em>str</em> 或字符 <em>ch</em></p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><em>str</em> 或 <em>ch</em>, <em>attr</em></p></td>
|
||||
<td><p>在当前位置使用 <em>attr</em> 属性显示字符串 <em>str</em> 或字符 <em>ch</em></p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><em>y</em>, <em>x</em>, <em>str</em> 或 <em>ch</em></p></td>
|
||||
<td><p>移动到窗口内的 <em>y,x</em> 位置,并显示 <em>str</em> 或 <em>ch</em></p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><em>y</em>, <em>x</em>, <em>str</em> 或 <em>ch</em>, <em>attr</em></p></td>
|
||||
<td><p>移至窗口内的 <em>y,x</em> 位置,并使用 <em>attr</em> 属性显示 <em>str</em> 或 <em>ch</em></p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>属性允许以突出显示形态显示文本,比如加粗、下划线、反相或添加颜色。这些属性将来下一小节细说。</p>
|
||||
<p>方法 <a class="reference internal" href="../library/curses.html#curses.window.addstr" title="curses.window.addstr"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addstr()</span></code></a> 接受一个 Python 字符串或字节串作为用于显示的值。字节串的内容会被原样发送到终端。字符串会使用窗口的 <code class="xref py py-attr docutils literal notranslate"><span class="pre">encoding</span></code> 属性值编码为字节,它默认为 <a class="reference internal" href="../library/locale.html#locale.getpreferredencoding" title="locale.getpreferredencoding"><code class="xref py py-func docutils literal notranslate"><span class="pre">locale.getpreferredencoding()</span></code></a> 返回的系统默认编码。</p>
|
||||
<p>方法 <a class="reference internal" href="../library/curses.html#curses.window.addch" title="curses.window.addch"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addch()</span></code></a> 接受一个字符,可以是长度为 1 的字符串,长度为 1 的字节串或者一个整数。</p>
|
||||
<p>对于特殊扩展字符有一些常量,这些常量是大于 255 的整数。比如,<code class="xref py py-const docutils literal notranslate"><span class="pre">ACS_PLMINUS</span></code> 是一个 “加减” 符号,<code class="xref py py-const docutils literal notranslate"><span class="pre">ACS_ULCORNER</span></code> 是一个框的左上角(方便绘制边界)。你也可以使用正确的 Unicode 字符。</p>
|
||||
<p>窗口会记住上次操作之后光标所在位置,所以如果你忽略 <em>y,x</em> 坐标,字符串和字符会出现在上次操作结束的位置。你也可以通过 <code class="docutils literal notranslate"><span class="pre">move(y,x)</span></code> 的方法来移动光标。因为一些终端始终会显示一个闪烁的光标,你可能会想要保证光标处于一些不会让人感到分心的位置。在看似随机的位置出现一个闪烁的光标会令人非常迷惑。</p>
|
||||
<p>如果你的应用程序完全不需要一个闪烁的光标,你可以调用 <code class="docutils literal notranslate"><span class="pre">curs_set(False)</span></code> 来使它隐形。为与旧版本 curses 的兼容性的关系,有函数 <code class="docutils literal notranslate"><span class="pre">leaveok(bool)</span></code> 作为 <a class="reference internal" href="../library/curses.html#curses.curs_set" title="curses.curs_set"><code class="xref py py-func docutils literal notranslate"><span class="pre">curs_set()</span></code></a> 的等价替换。如果 <em>bool</em> 是真值,curses 库会尝试移除闪烁光标,并且你也不必担心它会留在一些奇怪的位置。</p>
|
||||
<section id="attributes-and-color">
|
||||
<h3>属性和颜色<a class="headerlink" href="#attributes-and-color" title="永久链接至标题">¶</a></h3>
|
||||
<p>字符可以以不同的方式显示。基于文本的应用程序常常以反相显示状态行,一个文本查看器可能需要突出显示某些单词。为了支持这种用法,curses 允许你为屏幕上的每个单元指定一个属性值。</p>
|
||||
<p>属性值是一个整数,它的每一个二进制位代表一个不同的属性。你可以尝试以多种不属性位组合来显示文本,但 curses 不保证所有的组合都是有效的,或者看上去有明显不同。这一点取决于用户终端的能力,所以最稳妥的方式是只采用最常见的有效属性,见下表。</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 37%" />
|
||||
<col style="width: 63%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>属性</p></th>
|
||||
<th class="head"><p>描述</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p><code class="xref py py-const docutils literal notranslate"><span class="pre">A_BLINK</span></code></p></td>
|
||||
<td><p>闪烁文字</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="xref py py-const docutils literal notranslate"><span class="pre">A_BOLD</span></code></p></td>
|
||||
<td><p>超亮或粗体文字</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="xref py py-const docutils literal notranslate"><span class="pre">A_DIM</span></code></p></td>
|
||||
<td><p>半明亮的文字</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="xref py py-const docutils literal notranslate"><span class="pre">A_REVERSE</span></code></p></td>
|
||||
<td><p>反相显示文本</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="xref py py-const docutils literal notranslate"><span class="pre">A_STANDOUT</span></code></p></td>
|
||||
<td><p>可用的最佳突出显示模式</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="xref py py-const docutils literal notranslate"><span class="pre">A_UNDERLINE</span></code></p></td>
|
||||
<td><p>带下划线的文字</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>所以,为了在屏幕顶部显示一个反相的状态行,你可以这么编写:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">stdscr</span><span class="o">.</span><span class="n">addstr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"Current mode: Typing mode"</span><span class="p">,</span>
|
||||
<span class="n">curses</span><span class="o">.</span><span class="n">A_REVERSE</span><span class="p">)</span>
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">refresh</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>curses 库还支持在提供了颜色功能的终端上显示颜色的功能。最常见的提供颜色的终端很可能是 Linux 控制台,采用了 xterms 配色方案。</p>
|
||||
<p>为了使用颜色,你必须在调用完函数 <a class="reference internal" href="../library/curses.html#curses.initscr" title="curses.initscr"><code class="xref py py-func docutils literal notranslate"><span class="pre">initscr()</span></code></a> 后尽快调用函数 <a class="reference internal" href="../library/curses.html#curses.start_color" title="curses.start_color"><code class="xref py py-func docutils literal notranslate"><span class="pre">start_color()</span></code></a>,来初始化默认颜色集 (<a class="reference internal" href="../library/curses.html#curses.wrapper" title="curses.wrapper"><code class="xref py py-func docutils literal notranslate"><span class="pre">curses.wrapper()</span></code></a> 函数自动完成了这一点)。 当它完成后,如果使用中的终端支持显示颜色, <a class="reference internal" href="../library/curses.html#curses.has_colors" title="curses.has_colors"><code class="xref py py-func docutils literal notranslate"><span class="pre">has_colors()</span></code></a> 会返回真值。 (注意:curses 使用美式拼写 “color”,而不是英式/加拿大拼写 “colour”。如果你习惯了英式拼写,你需要避免自己在这些函数上拼写错误。)</p>
|
||||
<p>curses 库维护一个有限数量的颜色对,包括一个前景(文本)色和一个背景色。你可以使用函数 <a class="reference internal" href="../library/curses.html#curses.color_pair" title="curses.color_pair"><code class="xref py py-func docutils literal notranslate"><span class="pre">color_pair()</span></code></a> 获得一个颜色对对应的属性值。它可以通过按位或运算与其他属性,比如 <code class="xref py py-const docutils literal notranslate"><span class="pre">A_REVERSE</span></code> 组合。但再说明一遍,这种组合并不保证在所有终端上都有效。</p>
|
||||
<p>一个样例,用 1 号颜色对显示一行文本:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">stdscr</span><span class="o">.</span><span class="n">addstr</span><span class="p">(</span><span class="s2">"Pretty text"</span><span class="p">,</span> <span class="n">curses</span><span class="o">.</span><span class="n">color_pair</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">refresh</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如前所述, 颜色对由前景色和背景色组成。 <code class="docutils literal notranslate"><span class="pre">init_pair(n,</span> <span class="pre">f,</span> <span class="pre">b)</span></code> 函数改变颜色对*n*的定义, 为前景色f和背景色b。 颜色对0硬连接到黑色上的白色,不能改变。</p>
|
||||
<p>颜色已经被编号,并且当其激活 color 模式时 <code class="xref py py-func docutils literal notranslate"><span class="pre">start_color()</span></code> 会初始化 8 种基本颜色。 它们是: 0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan 和 7:white。 <a class="reference internal" href="../library/curses.html#module-curses" title="curses: An interface to the curses library, providing portable terminal handling. (Unix)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">curses</span></code></a> 模块为这些颜色定义了相应的名称常量: <code class="xref py py-const docutils literal notranslate"><span class="pre">curses.COLOR_BLACK</span></code>, <code class="xref py py-const docutils literal notranslate"><span class="pre">curses.COLOR_RED</span></code> 等等。</p>
|
||||
<p>让我们来做个综合练习。 要将颜色 1 改为红色文本白色背景,你应当调用:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">curses</span><span class="o">.</span><span class="n">init_pair</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">curses</span><span class="o">.</span><span class="n">COLOR_RED</span><span class="p">,</span> <span class="n">curses</span><span class="o">.</span><span class="n">COLOR_WHITE</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>当你改变一个颜色对时,任何已经使用该颜色对来显示的文本将会更改为新的颜色。 你还可以这样来显示新颜色的文本:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">stdscr</span><span class="o">.</span><span class="n">addstr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span> <span class="s2">"RED ALERT!"</span><span class="p">,</span> <span class="n">curses</span><span class="o">.</span><span class="n">color_pair</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>某些非常花哨的终端可以将实际颜色定义修改为给定的 RGB 值。 这允许你将通常为红色的 1 号颜色改成紫色或蓝色或者任何你喜欢的颜色。 不幸的是,Linux 控制台不支持此特性,所以我无法尝试它,也无法提供任何示例。 想要检查你的终端是否能做到你可以调用 <a class="reference internal" href="../library/curses.html#curses.can_change_color" title="curses.can_change_color"><code class="xref py py-func docutils literal notranslate"><span class="pre">can_change_color()</span></code></a>,如果有此功能则它将返回 <code class="docutils literal notranslate"><span class="pre">True</span></code>。 如果你幸运地拥有一个如此优秀的终端,请查询你的系统的帮助页面来了解详情。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="user-input">
|
||||
<h2>用户输入<a class="headerlink" href="#user-input" title="永久链接至标题">¶</a></h2>
|
||||
<p>C curses 库提供了非常简单的输入机制。 Python 的 <a class="reference internal" href="../library/curses.html#module-curses" title="curses: An interface to the curses library, providing portable terminal handling. (Unix)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">curses</span></code></a> 模块添加了一个基本的文本输入控件。 (其他的库例如 <a class="reference external" href="https://pypi.org/project/urwid/">Urwid</a> 拥有更丰富的控件集。)</p>
|
||||
<p>有两个方法可以从窗口获取输入:</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../library/curses.html#curses.window.getch" title="curses.window.getch"><code class="xref py py-meth docutils literal notranslate"><span class="pre">getch()</span></code></a> 会刷新屏幕然后等待用户按键,如果之前调用过 <a class="reference internal" href="../library/curses.html#curses.echo" title="curses.echo"><code class="xref py py-func docutils literal notranslate"><span class="pre">echo()</span></code></a> 还会显示所按的键。 你还可以选择指定一个坐标以便在暂停之前让光标移动到那里。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/curses.html#curses.window.getkey" title="curses.window.getkey"><code class="xref py py-meth docutils literal notranslate"><span class="pre">getkey()</span></code></a> 将做同样的事但是会把整数转换为字符串。 每个字符将返回为长度为 1 个字符的字符串,特殊键例如函数键将返回包含键名的较长字符串例如 <code class="docutils literal notranslate"><span class="pre">KEY_UP</span></code> 或 <code class="docutils literal notranslate"><span class="pre">^G</span></code>。</p></li>
|
||||
</ul>
|
||||
<p>使用 <a class="reference internal" href="../library/curses.html#curses.window.nodelay" title="curses.window.nodelay"><code class="xref py py-meth docutils literal notranslate"><span class="pre">nodelay()</span></code></a> 窗口方法可以做到不等待用户。 在 <code class="docutils literal notranslate"><span class="pre">nodelay(True)</span></code> 之后,窗口的 <code class="xref py py-meth docutils literal notranslate"><span class="pre">getch()</span></code> 和 <code class="xref py py-meth docutils literal notranslate"><span class="pre">getkey()</span></code> 将成为非阻塞的。 为表明输入未就绪,<code class="xref py py-meth docutils literal notranslate"><span class="pre">getch()</span></code> 会返回 <code class="docutils literal notranslate"><span class="pre">curses.ERR</span></code> (值为 -1) 而 <code class="xref py py-meth docutils literal notranslate"><span class="pre">getkey()</span></code> 会引发异常。 此外还有 <a class="reference internal" href="../library/curses.html#curses.halfdelay" title="curses.halfdelay"><code class="xref py py-func docutils literal notranslate"><span class="pre">halfdelay()</span></code></a> 函数,它可被用来(实际地)在每个 <code class="xref py py-meth docutils literal notranslate"><span class="pre">getch()</span></code> 上设置一个计时器;如果在指定的延迟内没有输入可用(以十分之一秒为单位),curses 将引发异常。</p>
|
||||
<p><code class="xref py py-meth docutils literal notranslate"><span class="pre">getch()</span></code> 方法返回一个整数;如果数值在 0 到 255 之间,它代表所按下键的 ASCII 码。 大于 255 的值为特殊键例如 Page Up, Home 或方向键等。 你可以将返回的值与 <code class="xref py py-const docutils literal notranslate"><span class="pre">curses.KEY_PPAGE</span></code>, <code class="xref py py-const docutils literal notranslate"><span class="pre">curses.KEY_HOME</span></code> 或 <code class="xref py py-const docutils literal notranslate"><span class="pre">curses.KEY_LEFT</span></code> 等常量做比较。 你的程序主循环看起来可能是这样:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||||
<span class="n">c</span> <span class="o">=</span> <span class="n">stdscr</span><span class="o">.</span><span class="n">getch</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">c</span> <span class="o">==</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">'p'</span><span class="p">):</span>
|
||||
<span class="n">PrintDocument</span><span class="p">()</span>
|
||||
<span class="k">elif</span> <span class="n">c</span> <span class="o">==</span> <span class="nb">ord</span><span class="p">(</span><span class="s1">'q'</span><span class="p">):</span>
|
||||
<span class="k">break</span> <span class="c1"># Exit the while loop</span>
|
||||
<span class="k">elif</span> <span class="n">c</span> <span class="o">==</span> <span class="n">curses</span><span class="o">.</span><span class="n">KEY_HOME</span><span class="p">:</span>
|
||||
<span class="n">x</span> <span class="o">=</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><a class="reference internal" href="../library/curses.ascii.html#module-curses.ascii" title="curses.ascii: Constants and set-membership functions for ASCII characters."><code class="xref py py-mod docutils literal notranslate"><span class="pre">curses.ascii</span></code></a> 模块提供了一些 ASCII 类成员函数,它们接受整数或长度为 1 个字符的字符串参数;这些函数在为这样的循环编写更具可读性的测试时可能会很有用。 它还提供了一些转换函数,它们接受整数或长度为 1 个字符的字符串参数并返回同样的类型。 例如,<a class="reference internal" href="../library/curses.ascii.html#curses.ascii.ctrl" title="curses.ascii.ctrl"><code class="xref py py-func docutils literal notranslate"><span class="pre">curses.ascii.ctrl()</span></code></a> 返回与其参数相对应的控制字符。</p>
|
||||
<p>还有一个可以提取整个字符串的方法 <a class="reference internal" href="../library/curses.html#curses.window.getstr" title="curses.window.getstr"><code class="xref py py-meth docutils literal notranslate"><span class="pre">getstr()</span></code></a>。 它并不经常被使用,因为它的功能相当受限;可用的编辑键只有 Backspace 和 Enter 键,它们会结束字符串。 也可以选择限制为固定数量的字符。</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">curses</span><span class="o">.</span><span class="n">echo</span><span class="p">()</span> <span class="c1"># Enable echoing of characters</span>
|
||||
|
||||
<span class="c1"># Get a 15-character string, with the cursor on the top line</span>
|
||||
<span class="n">s</span> <span class="o">=</span> <span class="n">stdscr</span><span class="o">.</span><span class="n">getstr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span> <span class="mi">15</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><a class="reference internal" href="../library/curses.html#module-curses.textpad" title="curses.textpad: Emacs-like input editing in a curses window."><code class="xref py py-mod docutils literal notranslate"><span class="pre">curses.textpad</span></code></a> 模块提供了一个文本框,它支持类似 Emacs 的键绑定集。 <a class="reference internal" href="../library/curses.html#curses.textpad.Textbox" title="curses.textpad.Textbox"><code class="xref py py-class docutils literal notranslate"><span class="pre">Textbox</span></code></a> 类的各种方法支持带输入验证的编辑及包含或不包含末尾空格地收集编辑结果。 下面是一个例子:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">curses</span>
|
||||
<span class="kn">from</span> <span class="nn">curses.textpad</span> <span class="kn">import</span> <span class="n">Textbox</span><span class="p">,</span> <span class="n">rectangle</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">stdscr</span><span class="p">):</span>
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">addstr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"Enter IM message: (hit Ctrl-G to send)"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">editwin</span> <span class="o">=</span> <span class="n">curses</span><span class="o">.</span><span class="n">newwin</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">30</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="n">rectangle</span><span class="p">(</span><span class="n">stdscr</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="o">+</span><span class="mi">5</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="o">+</span><span class="mi">30</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">stdscr</span><span class="o">.</span><span class="n">refresh</span><span class="p">()</span>
|
||||
|
||||
<span class="n">box</span> <span class="o">=</span> <span class="n">Textbox</span><span class="p">(</span><span class="n">editwin</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Let the user edit until Ctrl-G is struck.</span>
|
||||
<span class="n">box</span><span class="o">.</span><span class="n">edit</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># Get resulting contents</span>
|
||||
<span class="n">message</span> <span class="o">=</span> <span class="n">box</span><span class="o">.</span><span class="n">gather</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>请查看 <a class="reference internal" href="../library/curses.html#module-curses.textpad" title="curses.textpad: Emacs-like input editing in a curses window."><code class="xref py py-mod docutils literal notranslate"><span class="pre">curses.textpad</span></code></a> 的库文档了解更多细节。</p>
|
||||
</section>
|
||||
<section id="for-more-information">
|
||||
<h2>更多的信息<a class="headerlink" href="#for-more-information" title="永久链接至标题">¶</a></h2>
|
||||
<p>本 HOWTO 没有涵盖一些进阶主题,例如读取屏幕的内容或从 xterm 实例捕获鼠标事件等,但是 <a class="reference internal" href="../library/curses.html#module-curses" title="curses: An interface to the curses library, providing portable terminal handling. (Unix)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">curses</span></code></a> 模块的 Python 库文档页面现在已相当完善。 接下来你应当去浏览一下其中的内容。</p>
|
||||
<p>如果你对 curses 函数的细节行为有疑问,请查看你的 curses 实现版本的说明页面,不论它是 ncurses 还是特定 Unix 厂商的版本。 说明页面将记录任何具体问题,并提供所有函数、属性以及可用 <code class="xref py py-const docutils literal notranslate"><span class="pre">ACS_*</span></code> 字符的完整列表。</p>
|
||||
<p>由于 curses API 是如此的庞大,某些函数并不被 Python 接口所支持。 这往往不是因为它们难以实现,而是因为还没有人需要它们。 此外,Python 尚不支持与 ncurses 相关联的菜单库。 欢迎提供添加这些功能的补丁;请参阅 <a class="reference external" href="https://devguide.python.org/">Python 开发者指南</a> 了解有关为 Python 提交补丁的详情。</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference external" href="http://invisible-island.net/ncurses/ncurses-intro.html">使用 NCURSES 编写程序</a>: 一篇面向 C 程序员的详细教程。</p></li>
|
||||
<li><p>ncurses 手册主页 <<a class="reference external" href="https://linux.die.net/man/3/ncurses">https://linux.die.net/man/3/ncurses</a>>`_</p></li>
|
||||
<li><p>ncurses 常见问题 <<a class="reference external" href="http://invisible-island.net/ncurses/ncurses.faq.html">http://invisible-island.net/ncurses/ncurses.faq.html</a>>`_</p></li>
|
||||
<li><p><a class="reference external" href="https://www.youtube.com/watch?v=eN1eZtjLEnU">"使用 curses... 请勿爆粗"</a>: 一场有关使用 curses 或 Urwid 来控制终端的 PyCon 2013 演讲的视频。</p></li>
|
||||
<li><p><a class="reference external" href="http://www.pyvideo.org/video/1568/console-applications-with-urwid">"使用 Urwid 的控制台应用程序"</a>: 一场演示使用 Urwid 编写应用程序的 PyCon CA 2012 演讲的视频。</p></li>
|
||||
</ul>
|
||||
</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="#">用 Python 进行 Curses 编程</a><ul>
|
||||
<li><a class="reference internal" href="#what-is-curses">curses 是什么?</a><ul>
|
||||
<li><a class="reference internal" href="#the-python-curses-module">Python 的 curses 模块</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#starting-and-ending-a-curses-application">开始和结束curses应用程序</a></li>
|
||||
<li><a class="reference internal" href="#windows-and-pads">窗口和面板</a></li>
|
||||
<li><a class="reference internal" href="#displaying-text">显示文字</a><ul>
|
||||
<li><a class="reference internal" href="#attributes-and-color">属性和颜色</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#user-input">用户输入</a></li>
|
||||
<li><a class="reference internal" href="#for-more-information">更多的信息</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="cporting.html"
|
||||
title="上一章">将扩展模块移植到 Python 3</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="descriptor.html"
|
||||
title="下一章">描述器使用指南</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/howto/curses.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="descriptor.html" title="描述器使用指南"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="cporting.html" title="将扩展模块移植到 Python 3"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
618
web/python-docs/howto/descriptor.html
Normal file
618
web/python-docs/howto/descriptor.html
Normal file
@@ -0,0 +1,618 @@
|
||||
|
||||
<!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>描述器使用指南 — 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="函数式编程指引" href="functional.html" />
|
||||
<link rel="prev" title="用 Python 进行 Curses 编程" href="curses.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/descriptor.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="#">描述器使用指南</a><ul>
|
||||
<li><a class="reference internal" href="#abstract">摘要</a></li>
|
||||
<li><a class="reference internal" href="#definition-and-introduction">定义和简介</a></li>
|
||||
<li><a class="reference internal" href="#descriptor-protocol">描述器协议</a></li>
|
||||
<li><a class="reference internal" href="#invoking-descriptors">调用描述器</a></li>
|
||||
<li><a class="reference internal" href="#descriptor-example">描述器示例</a></li>
|
||||
<li><a class="reference internal" href="#properties">属性</a></li>
|
||||
<li><a class="reference internal" href="#functions-and-methods">函数和方法</a></li>
|
||||
<li><a class="reference internal" href="#static-methods-and-class-methods">静态方法和类方法</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="curses.html"
|
||||
title="上一章">用 Python 进行 Curses 编程</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="functional.html"
|
||||
title="下一章">函数式编程指引</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/howto/descriptor.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/howto/descriptor.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="functional.html" title="函数式编程指引"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="curses.html" title="用 Python 进行 Curses 编程"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="descriptor-howto-guide">
|
||||
<h1><a class="toc-backref" href="#id2">描述器使用指南</a><a class="headerlink" href="#descriptor-howto-guide" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>Raymond Hettinger</p>
|
||||
</dd>
|
||||
<dt class="field-even">联系方式</dt>
|
||||
<dd class="field-even"><p><python at rcn dot com></p>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="contents topic" id="id1">
|
||||
<p class="topic-title">目录</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="#descriptor-howto-guide" id="id2">描述器使用指南</a></p>
|
||||
<ul>
|
||||
<li><p><a class="reference internal" href="#abstract" id="id3">摘要</a></p></li>
|
||||
<li><p><a class="reference internal" href="#definition-and-introduction" id="id4">定义和简介</a></p></li>
|
||||
<li><p><a class="reference internal" href="#descriptor-protocol" id="id5">描述器协议</a></p></li>
|
||||
<li><p><a class="reference internal" href="#invoking-descriptors" id="id6">调用描述器</a></p></li>
|
||||
<li><p><a class="reference internal" href="#descriptor-example" id="id7">描述器示例</a></p></li>
|
||||
<li><p><a class="reference internal" href="#properties" id="id8">属性</a></p></li>
|
||||
<li><p><a class="reference internal" href="#functions-and-methods" id="id9">函数和方法</a></p></li>
|
||||
<li><p><a class="reference internal" href="#static-methods-and-class-methods" id="id10">静态方法和类方法</a></p></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<section id="abstract">
|
||||
<h2><a class="toc-backref" href="#id3">摘要</a><a class="headerlink" href="#abstract" title="永久链接至标题">¶</a></h2>
|
||||
<p>定义描述器,总结描述器协议,展示描述器被如何使用。测试一个自定义的描述器和若干 Python 内置的描述器,包括函数、属性、静态方法和类方法。通过给出一个纯 Python 的等价实现和例程,展示每个描述器如何工作。</p>
|
||||
<p>学习描述器不仅能提供接触到更多工具集的途径,还能更深地理解 Python 工作的原理并更加体会到其设计的优雅性。</p>
|
||||
</section>
|
||||
<section id="definition-and-introduction">
|
||||
<h2><a class="toc-backref" href="#id4">定义和简介</a><a class="headerlink" href="#definition-and-introduction" title="永久链接至标题">¶</a></h2>
|
||||
<p>一般地,一个描述器是一个包含 “绑定行为” 的对象,对其属性的访问被描述器协议中定义的方法覆盖。这些方法有:<a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code></a>,<a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code></a> 和 <a class="reference internal" href="../reference/datamodel.html#object.__delete__" title="object.__delete__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__delete__()</span></code></a>。如果某个对象中定义了这些方法中的任意一个,那么这个对象就可以被称为一个描述器。</p>
|
||||
<p>属性访问的默认行为是从一个对象的字典中获取、设置或删除属性。例如,<code class="docutils literal notranslate"><span class="pre">a.x</span></code> 的查找顺序会从 <code class="docutils literal notranslate"><span class="pre">a.__dict__['x']</span></code> 开始,然后是 <code class="docutils literal notranslate"><span class="pre">type(a).__dict__['x']</span></code>,接下来依次查找 <code class="docutils literal notranslate"><span class="pre">type(a)</span></code> 的基类,不包括元类。 如果找到的值是定义了某个描述器方法的对象,则 Python 可能会重载默认行为并转而发起调用描述器方法。这具体发生在优先级链的哪个环节则要根据所定义的描述器方法及其被调用的方式来决定。</p>
|
||||
<p>描述器是一个强大而通用的协议。 它们是特征属性、方法静态方法、类方法和 <a class="reference internal" href="../library/functions.html#super" title="super"><code class="xref py py-func docutils literal notranslate"><span class="pre">super()</span></code></a> 背后的实现机制。 它们在 Python 内部被广泛使用来实现自 2.2 版中引入的新式类。 描述器简化了底层的 C 代码并为 Python 的日常程序提供了一组灵活的新工具。</p>
|
||||
</section>
|
||||
<section id="descriptor-protocol">
|
||||
<h2><a class="toc-backref" href="#id5">描述器协议</a><a class="headerlink" href="#descriptor-protocol" title="永久链接至标题">¶</a></h2>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">descr.__get__(self,</span> <span class="pre">obj,</span> <span class="pre">type=None)</span> <span class="pre">-></span> <span class="pre">value</span></code></p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">descr.__set__(self,</span> <span class="pre">obj,</span> <span class="pre">value)</span> <span class="pre">-></span> <span class="pre">None</span></code></p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">descr.__delete__(self,</span> <span class="pre">obj)</span> <span class="pre">-></span> <span class="pre">None</span></code></p>
|
||||
<p>以上就是全部。定义这些方法中的任何一个的对象被视为描述器,并在被作为属性时覆盖其默认行为。</p>
|
||||
<p>如果一个对象定义了 <a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code></a> 或 <a class="reference internal" href="../reference/datamodel.html#object.__delete__" title="object.__delete__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__delete__()</span></code></a>,则它会被视为数据描述器。 仅定义了 <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code></a> 的描述器称为非数据描述器(它们通常被用于方法,但也可以有其他用途)。</p>
|
||||
<p>数据和非数据描述器的不同之处在于,如何计算实例字典中条目的替代值。如果实例的字典具有与数据描述器同名的条目,则数据描述器优先。如果实例的字典具有与非数据描述器同名的条目,则该字典条目优先。</p>
|
||||
<p>为了使数据描述器成为只读的,应该同时定义 <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code></a> 和 <a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code></a> ,并在 <a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code></a> 中引发 <a class="reference internal" href="../library/exceptions.html#AttributeError" title="AttributeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">AttributeError</span></code></a> 。用引发异常的占位符定义 <a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__set__()</span></code></a> 方法使其成为数据描述器。</p>
|
||||
</section>
|
||||
<section id="invoking-descriptors">
|
||||
<h2><a class="toc-backref" href="#id6">调用描述器</a><a class="headerlink" href="#invoking-descriptors" title="永久链接至标题">¶</a></h2>
|
||||
<p>描述器可以通过其方法名称直接调用。例如, <code class="docutils literal notranslate"><span class="pre">d.__get__(obj)</span></code> 。</p>
|
||||
<p>或者,更常见的是在属性访问时自动调用描述器。例如,在中 <code class="docutils literal notranslate"><span class="pre">obj.d</span></code> 会在 <code class="docutils literal notranslate"><span class="pre">d</span></code> 的字典中查找 <code class="docutils literal notranslate"><span class="pre">obj</span></code> 。如果 <code class="docutils literal notranslate"><span class="pre">d</span></code> 定义了方法 <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code></a> ,则 <code class="docutils literal notranslate"><span class="pre">d.__get__(obj)</span></code> 根据下面列出的优先级规则进行调用。</p>
|
||||
<p>调用的细节取决于 <code class="docutils literal notranslate"><span class="pre">obj</span></code> 是对象还是类。</p>
|
||||
<p>对于对象来说,机制是 <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">object.__getattribute__()</span></code></a> 中将 <code class="docutils literal notranslate"><span class="pre">b.x</span></code> 转换为 <code class="docutils literal notranslate"><span class="pre">type(b).__dict__['x'].__get__(b,</span> <span class="pre">type(b))</span></code> 。这个实现通过一个优先级链完成,该优先级链赋予数据描述器优先于实例变量的优先级,实例变量优先于非数据描述器的优先级,并如果 <a class="reference internal" href="../reference/datamodel.html#object.__getattr__" title="object.__getattr__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattr__()</span></code></a> 方法存在,为其分配最低的优先级。 完整的C实现可在 <a class="reference external" href="https://github.com/python/cpython/tree/3.8/Objects/object.c">Objects/object.c</a> 中的 <a class="reference internal" href="../c-api/object.html#c.PyObject_GenericGetAttr" title="PyObject_GenericGetAttr"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_GenericGetAttr()</span></code></a> 找到。</p>
|
||||
<p>对于类来说,机制是 <code class="xref py py-meth docutils literal notranslate"><span class="pre">type.__getattribute__()</span></code> 中将 <code class="docutils literal notranslate"><span class="pre">B.x</span></code> 转换为 <code class="docutils literal notranslate"><span class="pre">B.__dict__['x'].__get__(None,</span> <span class="pre">B)</span></code> 。在纯 Python中 ,它是这样的:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="fm">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
|
||||
<span class="s2">"Emulate type_getattro() in Objects/typeobject.c"</span>
|
||||
<span class="n">v</span> <span class="o">=</span> <span class="nb">object</span><span class="o">.</span><span class="fm">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="s1">'__get__'</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">v</span><span class="o">.</span><span class="fm">__get__</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">v</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>要记住的重要点是:</p>
|
||||
<ul class="simple">
|
||||
<li><p>描述器由 <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code></a> 方法调用</p></li>
|
||||
<li><p>重写 <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code></a> 会阻止描述器的自动调用</p></li>
|
||||
<li><p><a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">object.__getattribute__()</span></code></a> 和 <code class="xref py py-meth docutils literal notranslate"><span class="pre">type.__getattribute__()</span></code> 会用不同的方式调用 <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code></a>.</p></li>
|
||||
<li><p>数据描述器始终会覆盖实例字典。</p></li>
|
||||
<li><p>非数据描述器会被实例字典覆盖。</p></li>
|
||||
</ul>
|
||||
<p>The object returned by <code class="docutils literal notranslate"><span class="pre">super()</span></code> also has a custom <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code></a>
|
||||
method for invoking descriptors. The attribute lookup <code class="docutils literal notranslate"><span class="pre">super(B,</span> <span class="pre">obj).m</span></code> searches
|
||||
<code class="docutils literal notranslate"><span class="pre">obj.__class__.__mro__</span></code> for the base class <code class="docutils literal notranslate"><span class="pre">A</span></code> immediately following <code class="docutils literal notranslate"><span class="pre">B</span></code>
|
||||
and then returns <code class="docutils literal notranslate"><span class="pre">A.__dict__['m'].__get__(obj,</span> <span class="pre">B)</span></code>. If not a descriptor,
|
||||
<code class="docutils literal notranslate"><span class="pre">m</span></code> is returned unchanged. If not in the dictionary, <code class="docutils literal notranslate"><span class="pre">m</span></code> reverts to a
|
||||
search using <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">object.__getattribute__()</span></code></a>.</p>
|
||||
<p>这个实现的具体细节在 <a class="reference external" href="https://github.com/python/cpython/tree/3.8/Objects/typeobject.c">Objects/typeobject.c</a>. 的 <code class="xref c c-func docutils literal notranslate"><span class="pre">super_getattro()</span></code> 中,并且你还可以在 <a class="reference external" href="https://www.python.org/download/releases/2.2.3/descrintro/#cooperation">Guido's Tutorial</a> 中找到等价的纯 Python 实现。</p>
|
||||
<p>以上展示的关于描述器机制的细节嵌入在 <a class="reference internal" href="../library/functions.html#object" title="object"><code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></a> , <a class="reference internal" href="../library/functions.html#type" title="type"><code class="xref py py-class docutils literal notranslate"><span class="pre">type</span></code></a> , 和 <a class="reference internal" href="../library/functions.html#super" title="super"><code class="xref py py-func docutils literal notranslate"><span class="pre">super()</span></code></a> 中的 <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code></a> 。当类派生自类 <a class="reference internal" href="../library/functions.html#object" title="object"><code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></a> 或有提供类似功能的元类时,它们将继承此机制。同样,类可以通过重写 <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code></a> 阻止描述器调用。</p>
|
||||
</section>
|
||||
<section id="descriptor-example">
|
||||
<h2><a class="toc-backref" href="#id7">描述器示例</a><a class="headerlink" href="#descriptor-example" title="永久链接至标题">¶</a></h2>
|
||||
<p>以下代码创建一个类,其对象是数据描述器,该描述器为每个 get 或 set 打印一条消息。 覆盖 <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__getattribute__()</span></code></a> 是可以对每个属性执行此操作的替代方法。但是,此描述器对于跟踪少数几个选定的属性很有用:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">RevealAccess</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="w"> </span><span class="sd">"""A data descriptor that sets and returns values</span>
|
||||
<span class="sd"> normally and prints a message logging their access.</span>
|
||||
<span class="sd"> """</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">initval</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'var'</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">val</span> <span class="o">=</span> <span class="n">initval</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'Retrieving'</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">val</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">val</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'Updating'</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">val</span> <span class="o">=</span> <span class="n">val</span>
|
||||
|
||||
<span class="o">>>></span> <span class="k">class</span> <span class="nc">MyClass</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="o">...</span> <span class="n">x</span> <span class="o">=</span> <span class="n">RevealAccess</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s1">'var "x"'</span><span class="p">)</span>
|
||||
<span class="o">...</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">5</span>
|
||||
<span class="o">...</span>
|
||||
<span class="o">>>></span> <span class="n">m</span> <span class="o">=</span> <span class="n">MyClass</span><span class="p">()</span>
|
||||
<span class="o">>>></span> <span class="n">m</span><span class="o">.</span><span class="n">x</span>
|
||||
<span class="n">Retrieving</span> <span class="n">var</span> <span class="s2">"x"</span>
|
||||
<span class="mi">10</span>
|
||||
<span class="o">>>></span> <span class="n">m</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="mi">20</span>
|
||||
<span class="n">Updating</span> <span class="n">var</span> <span class="s2">"x"</span>
|
||||
<span class="o">>>></span> <span class="n">m</span><span class="o">.</span><span class="n">x</span>
|
||||
<span class="n">Retrieving</span> <span class="n">var</span> <span class="s2">"x"</span>
|
||||
<span class="mi">20</span>
|
||||
<span class="o">>>></span> <span class="n">m</span><span class="o">.</span><span class="n">y</span>
|
||||
<span class="mi">5</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这个协议很简单,并提供了令人兴奋的可能性。有几种用例非常普遍,以至于它们被打包到单独的函数调用中。属性、绑定方法、静态方法和类方法均基于描述器协议。</p>
|
||||
</section>
|
||||
<section id="properties">
|
||||
<h2><a class="toc-backref" href="#id8">属性</a><a class="headerlink" href="#properties" title="永久链接至标题">¶</a></h2>
|
||||
<p>调用 <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a> 是构建数据描述器的简洁方式,该数据描述器在访问属性时触发函数调用。它的签名是:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nb">property</span><span class="p">(</span><span class="n">fget</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fset</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fdel</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="o">-></span> <span class="nb">property</span> <span class="n">attribute</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>该文档显示了定义托管属性 <code class="docutils literal notranslate"><span class="pre">x</span></code> 的典型用法:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="k">def</span> <span class="nf">getx</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__x</span>
|
||||
<span class="k">def</span> <span class="nf">setx</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">__x</span> <span class="o">=</span> <span class="n">value</span>
|
||||
<span class="k">def</span> <span class="nf">delx</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">__x</span>
|
||||
<span class="n">x</span> <span class="o">=</span> <span class="nb">property</span><span class="p">(</span><span class="n">getx</span><span class="p">,</span> <span class="n">setx</span><span class="p">,</span> <span class="n">delx</span><span class="p">,</span> <span class="s2">"I'm the 'x' property."</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>要了解 <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a> 如何根据描述器协议实现,这里是一个纯 Python 的等价实现如下:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Property</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="s2">"Emulate PyProperty_Type() in Objects/descrobject.c"</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">fget</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fset</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">fdel</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">fget</span> <span class="o">=</span> <span class="n">fget</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">fset</span> <span class="o">=</span> <span class="n">fset</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">fdel</span> <span class="o">=</span> <span class="n">fdel</span>
|
||||
<span class="k">if</span> <span class="n">doc</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">fget</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">doc</span> <span class="o">=</span> <span class="n">fget</span><span class="o">.</span><span class="vm">__doc__</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span> <span class="o">=</span> <span class="n">doc</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fget</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="s2">"unreadable attribute"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">fget</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fset</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="s2">"can't set attribute"</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">fset</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__delete__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="s2">"can't delete attribute"</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">fdel</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">getter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fget</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)(</span><span class="n">fget</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fset</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fset</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)(</span><span class="bp">self</span><span class="o">.</span><span class="n">fget</span><span class="p">,</span> <span class="n">fset</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">deleter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fdel</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)(</span><span class="bp">self</span><span class="o">.</span><span class="n">fget</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fset</span><span class="p">,</span> <span class="n">fdel</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__doc__</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这个内置的 <a class="reference internal" href="../library/functions.html#property" title="property"><code class="xref py py-func docutils literal notranslate"><span class="pre">property()</span></code></a> 每当用户访问属性时生效,随后的变化需要一个方法的参与。</p>
|
||||
<p>例如,一个电子表格类可以通过 <code class="docutils literal notranslate"><span class="pre">Cell('b10').value</span></code> 授予对单元格值的访问权限。对程序的后续改进要求每次访问都要重新计算单元格;但是,程序员不希望影响直接访问该属性的现有客户端代码。解决方案是将对 value 属性的访问包装在属性数据描述器中:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Cell</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="o">.</span> <span class="o">.</span> <span class="o">.</span>
|
||||
<span class="k">def</span> <span class="nf">getvalue</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="s2">"Recalculate the cell before returning value"</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">recalc</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_value</span>
|
||||
<span class="n">value</span> <span class="o">=</span> <span class="nb">property</span><span class="p">(</span><span class="n">getvalue</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="functions-and-methods">
|
||||
<h2><a class="toc-backref" href="#id9">函数和方法</a><a class="headerlink" href="#functions-and-methods" title="永久链接至标题">¶</a></h2>
|
||||
<p>Python 的面向对象功能是在基于函数的环境构建的。通过使用非数据描述器,这两方面完成了无缝融合。</p>
|
||||
<p>类字典将方法存储为函数。在类定义中,方法是用 <a class="reference internal" href="../reference/compound_stmts.html#def"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">def</span></code></a> 或 <a class="reference internal" href="../reference/expressions.html#lambda"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">lambda</span></code></a> 这两个创建函数的常用工具编写的。方法与常规函数的不同之处仅在于第一个参数是为对象实例保留的。按照 Python 约定,实例引用称为 <em>self</em> ,但也可以称为 <em>this</em> 或任何其他变量名称。</p>
|
||||
<p>为了支持方法调用,函数包含 <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code></a> 方法用于在访问属性时将其绑定成方法。这意味着所有函数都是非数据描述器,当从对象调用它们时,它们返回绑定方法。在纯 Python 中,它的工作方式如下:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Function</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="o">.</span> <span class="o">.</span> <span class="o">.</span>
|
||||
<span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="s2">"Simulate func_descr_get() in Objects/funcobject.c"</span>
|
||||
<span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span>
|
||||
<span class="k">return</span> <span class="n">types</span><span class="o">.</span><span class="n">MethodType</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>运行解释器显示了函数描述器在实践中的工作方式:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">class</span> <span class="nc">D</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="k">return</span> <span class="n">x</span>
|
||||
<span class="gp">...</span>
|
||||
<span class="gp">>>> </span><span class="n">d</span> <span class="o">=</span> <span class="n">D</span><span class="p">()</span>
|
||||
|
||||
<span class="go"># Access through the class dictionary does not invoke __get__.</span>
|
||||
<span class="go"># It just returns the underlying function object.</span>
|
||||
<span class="gp">>>> </span><span class="n">D</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="s1">'f'</span><span class="p">]</span>
|
||||
<span class="go"><function D.f at 0x00C45070></span>
|
||||
|
||||
<span class="go"># Dotted access from a class calls __get__() which just returns</span>
|
||||
<span class="go"># the underlying function unchanged.</span>
|
||||
<span class="gp">>>> </span><span class="n">D</span><span class="o">.</span><span class="n">f</span>
|
||||
<span class="go"><function D.f at 0x00C45070></span>
|
||||
|
||||
<span class="go"># The function has a __qualname__ attribute to support introspection</span>
|
||||
<span class="gp">>>> </span><span class="n">D</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="vm">__qualname__</span>
|
||||
<span class="go">'D.f'</span>
|
||||
|
||||
<span class="go"># Dotted access from an instance calls __get__() which returns the</span>
|
||||
<span class="go"># function wrapped in a bound method object</span>
|
||||
<span class="gp">>>> </span><span class="n">d</span><span class="o">.</span><span class="n">f</span>
|
||||
<span class="go"><bound method D.f of <__main__.D object at 0x00B18C90>></span>
|
||||
|
||||
<span class="go"># Internally, the bound method stores the underlying function and</span>
|
||||
<span class="go"># the bound instance.</span>
|
||||
<span class="gp">>>> </span><span class="n">d</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="vm">__func__</span>
|
||||
<span class="go"><function D.f at 0x1012e5ae8></span>
|
||||
<span class="gp">>>> </span><span class="n">d</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="vm">__self__</span>
|
||||
<span class="go"><__main__.D object at 0x1012e1f98></span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="static-methods-and-class-methods">
|
||||
<h2><a class="toc-backref" href="#id10">静态方法和类方法</a><a class="headerlink" href="#static-methods-and-class-methods" title="永久链接至标题">¶</a></h2>
|
||||
<p>非数据描述器为把函数绑定为方法的通常模式提供了一种简单的机制。</p>
|
||||
<p>概括地说,函数具有 <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__get__()</span></code></a> 方法,以便在作为属性访问时可以将其转换为方法。非数据描述符将 <code class="docutils literal notranslate"><span class="pre">obj.f(*args)</span></code> 的调用转换为 <code class="docutils literal notranslate"><span class="pre">f(obj,</span> <span class="pre">*args)</span></code> 。调用 <cite>klass.f(*args)`</cite> 因而变成 <code class="docutils literal notranslate"><span class="pre">f(*args)</span></code> 。</p>
|
||||
<p>下表总结了绑定及其两个最有用的变体:</p>
|
||||
<blockquote>
|
||||
<div><table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 30%" />
|
||||
<col style="width: 39%" />
|
||||
<col style="width: 32%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>转换形式</p></th>
|
||||
<th class="head"><p>通过对象调用</p></th>
|
||||
<th class="head"><p>通过类调用</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p>function -- 函数</p></td>
|
||||
<td><p>f(obj, *args)</p></td>
|
||||
<td><p>f(*args)</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p>静态方法</p></td>
|
||||
<td><p>f(*args)</p></td>
|
||||
<td><p>f(*args)</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p>类方法</p></td>
|
||||
<td><p>f(type(obj), *args)</p></td>
|
||||
<td><p>f(klass, *args)</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></blockquote>
|
||||
<p>静态方法返回底层函数,不做任何更改。调用 <code class="docutils literal notranslate"><span class="pre">c.f</span></code> 或 <code class="docutils literal notranslate"><span class="pre">C.f</span></code> 等效于通过 <code class="docutils literal notranslate"><span class="pre">object.__getattribute__(c,</span> <span class="pre">"f")</span></code> 或 <code class="docutils literal notranslate"><span class="pre">object.__getattribute__(C,</span> <span class="pre">"f")</span></code> 查找。这样该函数就可以从对象或类中进行相同的访问。</p>
|
||||
<p>适合于作为静态方法的是那些不引用 <code class="docutils literal notranslate"><span class="pre">self</span></code> 变量的方法。</p>
|
||||
<p>例如,一个统计用的包可能包含一个实验数据的容器类。该容器类提供了用于计算数据的平均值,均值,中位数和其他描述性统计信息的常规方法。但是,可能有在概念上相关但不依赖于数据的函数。例如, <code class="docutils literal notranslate"><span class="pre">erf(x)</span></code> 是在统计中的便捷转换,但并不直接依赖于特定的数据集。可以从对象或类中调用它: <code class="docutils literal notranslate"><span class="pre">s.erf(1.5)</span> <span class="pre">--></span> <span class="pre">.9332</span></code> 或 <code class="docutils literal notranslate"><span class="pre">Sample.erf(1.5)</span> <span class="pre">--></span> <span class="pre">.9332</span></code>。</p>
|
||||
<p>由于静态方法直接返回了底层的函数,因此示例调用是相同的:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">class</span> <span class="nc">E</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="k">def</span> <span class="nf">f</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="n">x</span><span class="p">)</span>
|
||||
<span class="gp">... </span> <span class="n">f</span> <span class="o">=</span> <span class="nb">staticmethod</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||||
<span class="gp">...</span>
|
||||
<span class="gp">>>> </span><span class="n">E</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
|
||||
<span class="go">3</span>
|
||||
<span class="gp">>>> </span><span class="n">E</span><span class="p">()</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
|
||||
<span class="go">3</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>使用非数据描述器,纯 Python 版本的 <a class="reference internal" href="../library/functions.html#staticmethod" title="staticmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">staticmethod()</span></code></a> 如下所示:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">StaticMethod</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="s2">"Emulate PyStaticMethod_Type() in Objects/funcobject.c"</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">f</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">f</span> <span class="o">=</span> <span class="n">f</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">f</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>与静态方法不同,类方法在调用函数之前将类引用放在参数列表的最前。无论调用方是对象还是类,此格式相同:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">class</span> <span class="nc">E</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">klass</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="k">return</span> <span class="n">klass</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span> <span class="n">x</span>
|
||||
<span class="gp">... </span> <span class="n">f</span> <span class="o">=</span> <span class="nb">classmethod</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||||
<span class="gp">...</span>
|
||||
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">E</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span>
|
||||
<span class="go">('E', 3)</span>
|
||||
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">E</span><span class="p">()</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span>
|
||||
<span class="go">('E', 3)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>此行为适用于当函数仅需要使用类引用并且不关心任何底层数据时的情况。 类方法的一种用途是创建替代的类构造器。 在 Python 2.3 中,类方法 <a class="reference internal" href="../library/stdtypes.html#dict.fromkeys" title="dict.fromkeys"><code class="xref py py-func docutils literal notranslate"><span class="pre">dict.fromkeys()</span></code></a> 会从键列表中创建一个新的字典。 纯 Python 的等价形式是:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Dict</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="o">.</span> <span class="o">.</span> <span class="o">.</span>
|
||||
<span class="k">def</span> <span class="nf">fromkeys</span><span class="p">(</span><span class="n">klass</span><span class="p">,</span> <span class="n">iterable</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="s2">"Emulate dict_fromkeys() in Objects/dictobject.c"</span>
|
||||
<span class="n">d</span> <span class="o">=</span> <span class="n">klass</span><span class="p">()</span>
|
||||
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">iterable</span><span class="p">:</span>
|
||||
<span class="n">d</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
|
||||
<span class="k">return</span> <span class="n">d</span>
|
||||
<span class="n">fromkeys</span> <span class="o">=</span> <span class="nb">classmethod</span><span class="p">(</span><span class="n">fromkeys</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>现在可以这样构造一个新的唯一键字典:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">Dict</span><span class="o">.</span><span class="n">fromkeys</span><span class="p">(</span><span class="s1">'abracadabra'</span><span class="p">)</span>
|
||||
<span class="go">{'a': None, 'r': None, 'b': None, 'c': None, 'd': None}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>使用非数据描述符协议,纯 Python 版本的 <a class="reference internal" href="../library/functions.html#classmethod" title="classmethod"><code class="xref py py-func docutils literal notranslate"><span class="pre">classmethod()</span></code></a> 如下:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ClassMethod</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
||||
<span class="s2">"Emulate PyClassMethod_Type() in Objects/funcobject.c"</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">f</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">f</span> <span class="o">=</span> <span class="n">f</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">klass</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">klass</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">klass</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||||
<span class="k">def</span> <span class="nf">newfunc</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="n">klass</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">newfunc</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</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="#">描述器使用指南</a><ul>
|
||||
<li><a class="reference internal" href="#abstract">摘要</a></li>
|
||||
<li><a class="reference internal" href="#definition-and-introduction">定义和简介</a></li>
|
||||
<li><a class="reference internal" href="#descriptor-protocol">描述器协议</a></li>
|
||||
<li><a class="reference internal" href="#invoking-descriptors">调用描述器</a></li>
|
||||
<li><a class="reference internal" href="#descriptor-example">描述器示例</a></li>
|
||||
<li><a class="reference internal" href="#properties">属性</a></li>
|
||||
<li><a class="reference internal" href="#functions-and-methods">函数和方法</a></li>
|
||||
<li><a class="reference internal" href="#static-methods-and-class-methods">静态方法和类方法</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="curses.html"
|
||||
title="上一章">用 Python 进行 Curses 编程</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="functional.html"
|
||||
title="下一章">函数式编程指引</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/howto/descriptor.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="functional.html" title="函数式编程指引"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="curses.html" title="用 Python 进行 Curses 编程"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
1089
web/python-docs/howto/functional.html
Normal file
1089
web/python-docs/howto/functional.html
Normal file
File diff suppressed because it is too large
Load Diff
272
web/python-docs/howto/index.html
Normal file
272
web/python-docs/howto/index.html
Normal file
@@ -0,0 +1,272 @@
|
||||
|
||||
<!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>Python 指南 — 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="将 Python 2 代码迁移到 Python 3" href="pyporting.html" />
|
||||
<link rel="prev" title="安装 Python 模块" href="../installing/index.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/index.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>
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="../installing/index.html"
|
||||
title="上一章">安装 Python 模块</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="pyporting.html"
|
||||
title="下一章">将 Python 2 代码迁移到 Python 3</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/howto/index.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/howto/index.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="pyporting.html" title="将 Python 2 代码迁移到 Python 3"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../installing/index.html" title="安装 Python 模块"
|
||||
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> »</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> »
|
||||
</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="python-howtos">
|
||||
<h1>Python 指南<a class="headerlink" href="#python-howtos" title="永久链接至标题">¶</a></h1>
|
||||
<p>就像 Linux 文档项目的指南合集一样,每篇文章尝试完全覆盖一个单独、特定的主题并提供比 Python 库参考更详细的指南。</p>
|
||||
<p>目前已有的指南如下:</p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="pyporting.html">将 Python 2 代码迁移到 Python 3</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="cporting.html">将扩展模块移植到 Python 3</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="curses.html">用 Python 进行 Curses 编程</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="descriptor.html">描述器使用指南</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="functional.html">函数式编程指引</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="logging.html">日志指南</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="logging-cookbook.html">日志专题手册</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="regex.html">正则表达式指南</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="sockets.html">套接字编程指南</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="sorting.html">排序指南</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="unicode.html">Unicode 指南</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="urllib2.html">如何利用 urllib 包获取网络资源</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="argparse.html">argparse 教程</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="ipaddress.html">ipaddress模块介绍</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="clinic.html">Argument Clinic 的用法</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="instrumentation.html">使用 DTrace 和 SystemTap 检测CPython</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="../installing/index.html"
|
||||
title="上一章">安装 Python 模块</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="pyporting.html"
|
||||
title="下一章">将 Python 2 代码迁移到 Python 3</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/howto/index.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="pyporting.html" title="将 Python 2 代码迁移到 Python 3"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../installing/index.html" title="安装 Python 模块"
|
||||
>上一页</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> »</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> »
|
||||
</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">
|
||||
© <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>
|
||||
642
web/python-docs/howto/instrumentation.html
Normal file
642
web/python-docs/howto/instrumentation.html
Normal file
@@ -0,0 +1,642 @@
|
||||
|
||||
<!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>使用 DTrace 和 SystemTap 检测CPython — 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="Python 常见问题" href="../faq/index.html" />
|
||||
<link rel="prev" title="Argument Clinic 的用法" href="clinic.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/instrumentation.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="#">使用 DTrace 和 SystemTap 检测CPython</a><ul>
|
||||
<li><a class="reference internal" href="#enabling-the-static-markers">启用静态标记</a></li>
|
||||
<li><a class="reference internal" href="#static-dtrace-probes">静态DTrace探针</a></li>
|
||||
<li><a class="reference internal" href="#static-systemtap-markers">静态SystemTap标记</a></li>
|
||||
<li><a class="reference internal" href="#available-static-markers">可用的静态标记</a></li>
|
||||
<li><a class="reference internal" href="#systemtap-tapsets">SystemTap Tapsets</a></li>
|
||||
<li><a class="reference internal" href="#examples">例子</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="clinic.html"
|
||||
title="上一章">Argument Clinic 的用法</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="../faq/index.html"
|
||||
title="下一章">Python 常见问题</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/howto/instrumentation.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/howto/instrumentation.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="../faq/index.html" title="Python 常见问题"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="clinic.html" title="Argument Clinic 的用法"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="instrumenting-cpython-with-dtrace-and-systemtap">
|
||||
<span id="instrumentation"></span><h1>使用 DTrace 和 SystemTap 检测CPython<a class="headerlink" href="#instrumenting-cpython-with-dtrace-and-systemtap" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>David Malcolm</p>
|
||||
</dd>
|
||||
<dt class="field-even">作者</dt>
|
||||
<dd class="field-even"><p>Łukasz Langa</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>DTrace和SystemTap是监控工具,它们都提供了一种检查计算机系统上的进程的方法。 它们都使用特定领域的语言,允许用户编写脚本,其中:</p>
|
||||
<blockquote>
|
||||
<div><ul class="simple">
|
||||
<li><p>进程监视的过滤器</p></li>
|
||||
<li><p>从感兴趣的进程中收集数据</p></li>
|
||||
<li><p>生成有关数据的报告</p></li>
|
||||
</ul>
|
||||
</div></blockquote>
|
||||
<p>从Python 3.6开始,CPython可以使用嵌入式“标记”构建,也称为“探测器”,可以通过DTrace或SystemTap脚本观察,从而更容易监视系统上的CPython进程正在做什么。</p>
|
||||
<div class="impl-detail compound">
|
||||
<p><strong>CPython implementation detail:</strong> DTrace标记是CPython解释器的实现细节。 不保证CPython版本之间的探针兼容性。 更改CPython版本时,DTrace脚本可能会停止工作或无法正常工作而不会发出警告。</p>
|
||||
</div>
|
||||
<section id="enabling-the-static-markers">
|
||||
<h2>启用静态标记<a class="headerlink" href="#enabling-the-static-markers" title="永久链接至标题">¶</a></h2>
|
||||
<p>macOS内置了对DTrace的支持。 在Linux上,为了使用SystemTap的嵌入式标记构建CPython,必须安装SystemTap开发工具。</p>
|
||||
<p>在Linux机器上,这可以通过:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>yum<span class="w"> </span>install<span class="w"> </span>systemtap-sdt-devel
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>或者:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>systemtap-sdt-dev
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>然后必须将CPython配置为``--with-dtrace``:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>checking for --with-dtrace... yes
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>在macOS上,您可以通过在后台运行Python进程列出可用的DTrace探测器,并列出Python程序提供的所有探测器:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3.6<span class="w"> </span>-q<span class="w"> </span><span class="p">&</span>
|
||||
<span class="gp">$ </span>sudo<span class="w"> </span>dtrace<span class="w"> </span>-l<span class="w"> </span>-P<span class="w"> </span>python<span class="nv">$!</span><span class="w"> </span><span class="c1"># or: dtrace -l -m python3.6</span>
|
||||
|
||||
<span class="go"> ID PROVIDER MODULE FUNCTION NAME</span>
|
||||
<span class="go">29564 python18035 python3.6 _PyEval_EvalFrameDefault function-entry</span>
|
||||
<span class="go">29565 python18035 python3.6 dtrace_function_entry function-entry</span>
|
||||
<span class="go">29566 python18035 python3.6 _PyEval_EvalFrameDefault function-return</span>
|
||||
<span class="go">29567 python18035 python3.6 dtrace_function_return function-return</span>
|
||||
<span class="go">29568 python18035 python3.6 collect gc-done</span>
|
||||
<span class="go">29569 python18035 python3.6 collect gc-start</span>
|
||||
<span class="go">29570 python18035 python3.6 _PyEval_EvalFrameDefault line</span>
|
||||
<span class="go">29571 python18035 python3.6 maybe_dtrace_line line</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>在Linux上,您可以通过查看是否包含“.note.stapsdt”部分来验证构建的二进制文件中是否存在SystemTap静态标记。</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>readelf<span class="w"> </span>-S<span class="w"> </span>./python<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>.note.stapsdt
|
||||
<span class="go">[30] .note.stapsdt NOTE 0000000000000000 00308d78</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如果您已将Python构建为共享库(使用--enable-shared),则需要在共享库中查找。 例如:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>readelf<span class="w"> </span>-S<span class="w"> </span>libpython3.3dm.so.1.0<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>.note.stapsdt
|
||||
<span class="go">[29] .note.stapsdt NOTE 0000000000000000 00365b68</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>足够现代的readelf命令可以打印元数据:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>readelf<span class="w"> </span>-n<span class="w"> </span>./python
|
||||
|
||||
<span class="go">Displaying notes found at file offset 0x00000254 with length 0x00000020:</span>
|
||||
<span class="go"> Owner Data size Description</span>
|
||||
<span class="go"> GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)</span>
|
||||
<span class="go"> OS: Linux, ABI: 2.6.32</span>
|
||||
|
||||
<span class="go">Displaying notes found at file offset 0x00000274 with length 0x00000024:</span>
|
||||
<span class="go"> Owner Data size Description</span>
|
||||
<span class="go"> GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)</span>
|
||||
<span class="go"> Build ID: df924a2b08a7e89f6e11251d4602022977af2670</span>
|
||||
|
||||
<span class="go">Displaying notes found at file offset 0x002d6c30 with length 0x00000144:</span>
|
||||
<span class="go"> Owner Data size Description</span>
|
||||
<span class="go"> stapsdt 0x00000031 NT_STAPSDT (SystemTap probe descriptors)</span>
|
||||
<span class="go"> Provider: python</span>
|
||||
<span class="go"> Name: gc__start</span>
|
||||
<span class="go"> Location: 0x00000000004371c3, Base: 0x0000000000630ce2, Semaphore: 0x00000000008d6bf6</span>
|
||||
<span class="go"> Arguments: -4@%ebx</span>
|
||||
<span class="go"> stapsdt 0x00000030 NT_STAPSDT (SystemTap probe descriptors)</span>
|
||||
<span class="go"> Provider: python</span>
|
||||
<span class="go"> Name: gc__done</span>
|
||||
<span class="go"> Location: 0x00000000004374e1, Base: 0x0000000000630ce2, Semaphore: 0x00000000008d6bf8</span>
|
||||
<span class="go"> Arguments: -8@%rax</span>
|
||||
<span class="go"> stapsdt 0x00000045 NT_STAPSDT (SystemTap probe descriptors)</span>
|
||||
<span class="go"> Provider: python</span>
|
||||
<span class="go"> Name: function__entry</span>
|
||||
<span class="go"> Location: 0x000000000053db6c, Base: 0x0000000000630ce2, Semaphore: 0x00000000008d6be8</span>
|
||||
<span class="go"> Arguments: 8@%rbp 8@%r12 -4@%eax</span>
|
||||
<span class="go"> stapsdt 0x00000046 NT_STAPSDT (SystemTap probe descriptors)</span>
|
||||
<span class="go"> Provider: python</span>
|
||||
<span class="go"> Name: function__return</span>
|
||||
<span class="go"> Location: 0x000000000053dba8, Base: 0x0000000000630ce2, Semaphore: 0x00000000008d6bea</span>
|
||||
<span class="go"> Arguments: 8@%rbp 8@%r12 -4@%eax</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>上述元数据包含SystemTap的信息,描述如何修补策略性放置的机器代码指令以启用SystemTap脚本使用的跟踪钩子。</p>
|
||||
</section>
|
||||
<section id="static-dtrace-probes">
|
||||
<h2>静态DTrace探针<a class="headerlink" href="#static-dtrace-probes" title="永久链接至标题">¶</a></h2>
|
||||
<p>下面的 DTrace 脚本示例可以用来显示一个 Python 脚本的调用/返回层次结构,只在调用名为 "start" 的函数内进行跟踪。换句话说,导入时的函数调用不会被列出。</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>self int indent;
|
||||
|
||||
python$target:::function-entry
|
||||
/copyinstr(arg1) == "start"/
|
||||
{
|
||||
self->trace = 1;
|
||||
}
|
||||
|
||||
python$target:::function-entry
|
||||
/self->trace/
|
||||
{
|
||||
printf("%d\t%*s:", timestamp, 15, probename);
|
||||
printf("%*s", self->indent, "");
|
||||
printf("%s:%s:%d\n", basename(copyinstr(arg0)), copyinstr(arg1), arg2);
|
||||
self->indent++;
|
||||
}
|
||||
|
||||
python$target:::function-return
|
||||
/self->trace/
|
||||
{
|
||||
self->indent--;
|
||||
printf("%d\t%*s:", timestamp, 15, probename);
|
||||
printf("%*s", self->indent, "");
|
||||
printf("%s:%s:%d\n", basename(copyinstr(arg0)), copyinstr(arg1), arg2);
|
||||
}
|
||||
|
||||
python$target:::function-return
|
||||
/copyinstr(arg1) == "start"/
|
||||
{
|
||||
self->trace = 0;
|
||||
}
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>它可以这样调用:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>sudo<span class="w"> </span>dtrace<span class="w"> </span>-q<span class="w"> </span>-s<span class="w"> </span>call_stack.d<span class="w"> </span>-c<span class="w"> </span><span class="s2">"python3.6 script.py"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>输出结果会像这样:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>156641360502280 function-entry:call_stack.py:start:23
|
||||
156641360518804 function-entry: call_stack.py:function_1:1
|
||||
156641360532797 function-entry: call_stack.py:function_3:9
|
||||
156641360546807 function-return: call_stack.py:function_3:10
|
||||
156641360563367 function-return: call_stack.py:function_1:2
|
||||
156641360578365 function-entry: call_stack.py:function_2:5
|
||||
156641360591757 function-entry: call_stack.py:function_1:1
|
||||
156641360605556 function-entry: call_stack.py:function_3:9
|
||||
156641360617482 function-return: call_stack.py:function_3:10
|
||||
156641360629814 function-return: call_stack.py:function_1:2
|
||||
156641360642285 function-return: call_stack.py:function_2:6
|
||||
156641360656770 function-entry: call_stack.py:function_3:9
|
||||
156641360669707 function-return: call_stack.py:function_3:10
|
||||
156641360687853 function-entry: call_stack.py:function_4:13
|
||||
156641360700719 function-return: call_stack.py:function_4:14
|
||||
156641360719640 function-entry: call_stack.py:function_5:18
|
||||
156641360732567 function-return: call_stack.py:function_5:21
|
||||
156641360747370 function-return:call_stack.py:start:28
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="static-systemtap-markers">
|
||||
<h2>静态SystemTap标记<a class="headerlink" href="#static-systemtap-markers" title="永久链接至标题">¶</a></h2>
|
||||
<p>使用 SystemTap 集成的底层方法是直接使用静态标记。 这需要你显式地说明包含它们的二进制文件。</p>
|
||||
<p>例如,这个SystemTap脚本可以用来显示Python脚本的调用/返回层次结构:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>probe process("python").mark("function__entry") {
|
||||
filename = user_string($arg1);
|
||||
funcname = user_string($arg2);
|
||||
lineno = $arg3;
|
||||
|
||||
printf("%s => %s in %s:%d\\n",
|
||||
thread_indent(1), funcname, filename, lineno);
|
||||
}
|
||||
|
||||
probe process("python").mark("function__return") {
|
||||
filename = user_string($arg1);
|
||||
funcname = user_string($arg2);
|
||||
lineno = $arg3;
|
||||
|
||||
printf("%s <= %s in %s:%d\\n",
|
||||
thread_indent(-1), funcname, filename, lineno);
|
||||
}
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>它可以这样调用:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>stap<span class="w"> </span><span class="se">\</span>
|
||||
<span class="w"> </span>show-call-hierarchy.stp<span class="w"> </span><span class="se">\</span>
|
||||
<span class="w"> </span>-c<span class="w"> </span><span class="s2">"./python test.py"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>输出结果会像这样:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>11408 python(8274): => __contains__ in Lib/_abcoll.py:362
|
||||
11414 python(8274): => __getitem__ in Lib/os.py:425
|
||||
11418 python(8274): => encode in Lib/os.py:490
|
||||
11424 python(8274): <= encode in Lib/os.py:493
|
||||
11428 python(8274): <= __getitem__ in Lib/os.py:426
|
||||
11433 python(8274): <= __contains__ in Lib/_abcoll.py:366
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>其中的列是:</p>
|
||||
<blockquote>
|
||||
<div><ul class="simple">
|
||||
<li><p>脚本开始后经过的微秒数</p></li>
|
||||
<li><p>可执行文件的名字</p></li>
|
||||
<li><p>进程的PID</p></li>
|
||||
</ul>
|
||||
</div></blockquote>
|
||||
<p>其余部分则表示脚本执行时的调用/返回层次结构。</p>
|
||||
<p>对于 <cite>--enable-shared</cite> 构建的CPython来说,这些标记是包含在libpython共享库中的,探针的点状路径需要反映这一点。比如上面例子中的这一行:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>probe process("python").mark("function__entry") {
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>应改为:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>probe process("python").library("libpython3.6dm.so.1.0").mark("function__entry") {
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>(假设是 CPython 3.6 的调试构建)</p>
|
||||
</section>
|
||||
<section id="available-static-markers">
|
||||
<h2>可用的静态标记<a class="headerlink" href="#available-static-markers" title="永久链接至标题">¶</a></h2>
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">function__entry(str filename, str funcname, int lineno)</code></dt>
|
||||
<dd><p>这个标记表示一个Python函数的执行已经开始。它只对纯 Python (字节码)函数触发。</p>
|
||||
<p>文件名、函数名和行号作为位置参数提供给跟踪脚本,必须使用 <code class="docutils literal notranslate"><span class="pre">$arg1</span></code>, <code class="docutils literal notranslate"><span class="pre">$arg2</span></code>, <code class="docutils literal notranslate"><span class="pre">$arg3</span></code> 访问:</p>
|
||||
<blockquote>
|
||||
<div><ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$arg1</span></code> : <code class="docutils literal notranslate"><span class="pre">(const</span> <span class="pre">char</span> <span class="pre">*)</span></code> 文件名,使用 <code class="docutils literal notranslate"><span class="pre">user_string($arg1)</span></code> 访问</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$arg2</span></code> : <code class="docutils literal notranslate"><span class="pre">(const</span> <span class="pre">char</span> <span class="pre">*)</span></code> 函数名,使用 <code class="docutils literal notranslate"><span class="pre">user_string($arg2)</span></code> 访问</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$arg3</span></code> : <code class="docutils literal notranslate"><span class="pre">int</span></code> 行号</p></li>
|
||||
</ul>
|
||||
</div></blockquote>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">function__return(str filename, str funcname, int lineno)</code></dt>
|
||||
<dd><p>这个标记与 <code class="xref c c-func docutils literal notranslate"><span class="pre">function__entry()</span></code> 相反,表示Python函数的执行已经结束 (通过 <code class="docutils literal notranslate"><span class="pre">return</span></code> 或者异常)。 它只对纯Python (字节码) 函数触发。</p>
|
||||
<p>参数和 <code class="xref c c-func docutils literal notranslate"><span class="pre">function__entry()</span></code> 相同</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">line(str filename, str funcname, int lineno)</code></dt>
|
||||
<dd><p>这个标记表示一个 Python 行即将被执行。它相当于用 Python 分析器逐行追踪。它不会在C函数中触发。</p>
|
||||
<p>参数和 <code class="xref c c-func docutils literal notranslate"><span class="pre">function__entry()</span></code> 相同</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">gc__start(int generation)</code></dt>
|
||||
<dd><p>当Python解释器启动一个垃圾回收循环时被触发。 <code class="docutils literal notranslate"><span class="pre">arg0</span></code> 是要扫描的生成器,如 <a class="reference internal" href="../library/gc.html#gc.collect" title="gc.collect"><code class="xref py py-func docutils literal notranslate"><span class="pre">gc.collect()</span></code></a>。</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">gc__done(long collected)</code></dt>
|
||||
<dd><p>当Python解释器完成一个垃圾回收循环时被触发。<code class="docutils literal notranslate"><span class="pre">arg0</span></code> 是收集到的对象的数量。</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">import__find__load__start(str modulename)</code></dt>
|
||||
<dd><p>在 <a class="reference internal" href="../library/importlib.html#module-importlib" title="importlib: The implementation of the import machinery."><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a> 试图查找并加载模块之前被触发。<code class="docutils literal notranslate"><span class="pre">arg0</span></code> 是模块名称。</p>
|
||||
<div class="versionadded">
|
||||
<p><span class="versionmodified added">3.7 新版功能.</span></p>
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">import__find__load__done(str modulename, int found)</code></dt>
|
||||
<dd><p>在 <a class="reference internal" href="../library/importlib.html#module-importlib" title="importlib: The implementation of the import machinery."><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a> 的 find_and_load 函数被调用后被触发 。<code class="docutils literal notranslate"><span class="pre">arg0</span></code> 是模块名称, <code class="docutils literal notranslate"><span class="pre">arg1</span></code> 表示模块是否成功加载。</p>
|
||||
<div class="versionadded">
|
||||
<p><span class="versionmodified added">3.7 新版功能.</span></p>
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">audit(str event, void *tuple)</code></dt>
|
||||
<dd><p>当 <a class="reference internal" href="../library/sys.html#sys.audit" title="sys.audit"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.audit()</span></code></a> 或 <a class="reference internal" href="../c-api/sys.html#c.PySys_Audit" title="PySys_Audit"><code class="xref c c-func docutils literal notranslate"><span class="pre">PySys_Audit()</span></code></a> 被调用时启动。 <code class="docutils literal notranslate"><span class="pre">arg0</span></code> 是事件名称的 C 字符串,<code class="docutils literal notranslate"><span class="pre">arg1</span></code> 是一个指向元组对象的 <a class="reference internal" href="../c-api/structures.html#c.PyObject" title="PyObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyObject</span></code></a> 指针。</p>
|
||||
<div class="versionadded">
|
||||
<p><span class="versionmodified added">3.8 新版功能.</span></p>
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
</section>
|
||||
<section id="systemtap-tapsets">
|
||||
<h2>SystemTap Tapsets<a class="headerlink" href="#systemtap-tapsets" title="永久链接至标题">¶</a></h2>
|
||||
<p>使用SystemTap集成的更高层次的方法是使用 "tapset" 。SystemTap 的等效库,它隐藏了静态标记的一些底层细节。</p>
|
||||
<p>这里是一个基于 CPython 的非共享构建的 tapset 文件。</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>/*
|
||||
Provide a higher-level wrapping around the function__entry and
|
||||
function__return markers:
|
||||
\*/
|
||||
probe python.function.entry = process("python").mark("function__entry")
|
||||
{
|
||||
filename = user_string($arg1);
|
||||
funcname = user_string($arg2);
|
||||
lineno = $arg3;
|
||||
frameptr = $arg4
|
||||
}
|
||||
probe python.function.return = process("python").mark("function__return")
|
||||
{
|
||||
filename = user_string($arg1);
|
||||
funcname = user_string($arg2);
|
||||
lineno = $arg3;
|
||||
frameptr = $arg4
|
||||
}
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如果这个文件安装在 SystemTap 的 tapset 目录下(例如``/usr/share/systemtap/tapset`` ),那么这些额外的探测点就会变得可用。</p>
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">python.function.entry(str filename, str funcname, int lineno, frameptr)</code></dt>
|
||||
<dd><p>这个探针点表示一个Python函数的执行已经开始。它只对纯Python (字节码)函数触发。</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="object">
|
||||
<dt>
|
||||
<code class="sig-name descname">python.function.return(str filename, str funcname, int lineno, frameptr)</code></dt>
|
||||
<dd><p>这个探针点是 <code class="docutils literal notranslate"><span class="pre">python.function.return</span></code> 的反义操作,表示一个 Python 函数的执行已经结束(或是通过 <code class="docutils literal notranslate"><span class="pre">return</span></code>,或是通过异常)。 它只会针对纯 Python(字节码)函数触发。</p>
|
||||
</dd></dl>
|
||||
|
||||
</section>
|
||||
<section id="examples">
|
||||
<h2>例子<a class="headerlink" href="#examples" title="永久链接至标题">¶</a></h2>
|
||||
<p>这个SystemTap脚本使用上面的tapset来更清晰地实现上面给出的跟踪Python函数调用层次结构的例子,而不需要直接命名静态标记。</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>probe python.function.entry
|
||||
{
|
||||
printf("%s => %s in %s:%d\n",
|
||||
thread_indent(1), funcname, filename, lineno);
|
||||
}
|
||||
|
||||
probe python.function.return
|
||||
{
|
||||
printf("%s <= %s in %s:%d\n",
|
||||
thread_indent(-1), funcname, filename, lineno);
|
||||
}
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>下面的脚本使用上面的tapset提供了所有运行中的CPython代码的顶部视图,显示了整个系统中每一秒钟最频繁输入的前20个字节码帧。</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>global fn_calls;
|
||||
|
||||
probe python.function.entry
|
||||
{
|
||||
fn_calls[pid(), filename, funcname, lineno] += 1;
|
||||
}
|
||||
|
||||
probe timer.ms(1000) {
|
||||
printf("\033[2J\033[1;1H") /* clear screen \*/
|
||||
printf("%6s %80s %6s %30s %6s\n",
|
||||
"PID", "FILENAME", "LINE", "FUNCTION", "CALLS")
|
||||
foreach ([pid, filename, funcname, lineno] in fn_calls- limit 20) {
|
||||
printf("%6d %80s %6d %30s %6d\n",
|
||||
pid, filename, lineno, funcname,
|
||||
fn_calls[pid, filename, funcname, lineno]);
|
||||
}
|
||||
delete fn_calls;
|
||||
}
|
||||
</pre></div>
|
||||
</div>
|
||||
</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="#">使用 DTrace 和 SystemTap 检测CPython</a><ul>
|
||||
<li><a class="reference internal" href="#enabling-the-static-markers">启用静态标记</a></li>
|
||||
<li><a class="reference internal" href="#static-dtrace-probes">静态DTrace探针</a></li>
|
||||
<li><a class="reference internal" href="#static-systemtap-markers">静态SystemTap标记</a></li>
|
||||
<li><a class="reference internal" href="#available-static-markers">可用的静态标记</a></li>
|
||||
<li><a class="reference internal" href="#systemtap-tapsets">SystemTap Tapsets</a></li>
|
||||
<li><a class="reference internal" href="#examples">例子</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="clinic.html"
|
||||
title="上一章">Argument Clinic 的用法</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="../faq/index.html"
|
||||
title="下一章">Python 常见问题</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/howto/instrumentation.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="../faq/index.html" title="Python 常见问题"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="clinic.html" title="Argument Clinic 的用法"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
526
web/python-docs/howto/ipaddress.html
Normal file
526
web/python-docs/howto/ipaddress.html
Normal file
@@ -0,0 +1,526 @@
|
||||
|
||||
<!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>ipaddress模块介绍 — 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="Argument Clinic 的用法" href="clinic.html" />
|
||||
<link rel="prev" title="argparse 教程" href="argparse.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/ipaddress.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="#">ipaddress模块介绍</a><ul>
|
||||
<li><a class="reference internal" href="#creating-address-network-interface-objects">创建 Address/Network/Interface 对象</a><ul>
|
||||
<li><a class="reference internal" href="#a-note-on-ip-versions">关于IP版本的说明</a></li>
|
||||
<li><a class="reference internal" href="#ip-host-addresses">IP主机地址</a></li>
|
||||
<li><a class="reference internal" href="#defining-networks">定义网络</a></li>
|
||||
<li><a class="reference internal" href="#host-interfaces">主机接口</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#inspecting-address-network-interface-objects">审查 Address/Network/Interface 对象</a></li>
|
||||
<li><a class="reference internal" href="#networks-as-lists-of-addresses">Network 作为 Address 列表</a></li>
|
||||
<li><a class="reference internal" href="#comparisons">比较运算</a></li>
|
||||
<li><a class="reference internal" href="#using-ip-addresses-with-other-modules">将IP地址与其他模块一起使用</a></li>
|
||||
<li><a class="reference internal" href="#getting-more-detail-when-instance-creation-fails">实例创建失败时获取更多详细信息</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="argparse.html"
|
||||
title="上一章">argparse 教程</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="clinic.html"
|
||||
title="下一章">Argument Clinic 的用法</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/howto/ipaddress.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/howto/ipaddress.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="clinic.html" title="Argument Clinic 的用法"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="argparse.html" title="argparse 教程"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="an-introduction-to-the-ipaddress-module">
|
||||
<span id="ipaddress-howto"></span><h1>ipaddress模块介绍<a class="headerlink" href="#an-introduction-to-the-ipaddress-module" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>Peter Moody</p>
|
||||
</dd>
|
||||
<dt class="field-even">作者</dt>
|
||||
<dd class="field-even"><p>Nick Coghlan</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="topic">
|
||||
<p class="topic-title">概述</p>
|
||||
<p>本文档旨在简要介绍 <a class="reference internal" href="../library/ipaddress.html#module-ipaddress" title="ipaddress: IPv4/IPv6 manipulation library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ipaddress</span></code></a> 模块。 它主要针对那些不熟悉 IP 网络术语的用户,但也可能对想要速览 <a class="reference internal" href="../library/ipaddress.html#module-ipaddress" title="ipaddress: IPv4/IPv6 manipulation library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ipaddress</span></code></a> 如何代表IP网络寻址概念的网络工程师有用。</p>
|
||||
</div>
|
||||
<section id="creating-address-network-interface-objects">
|
||||
<h2>创建 Address/Network/Interface 对象<a class="headerlink" href="#creating-address-network-interface-objects" title="永久链接至标题">¶</a></h2>
|
||||
<p>因为 <a class="reference internal" href="../library/ipaddress.html#module-ipaddress" title="ipaddress: IPv4/IPv6 manipulation library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ipaddress</span></code></a> 是一个用于检查和操作 IP 地址的模块,你要做的第一件事就是创建一些对象。 您可以使用 <a class="reference internal" href="../library/ipaddress.html#module-ipaddress" title="ipaddress: IPv4/IPv6 manipulation library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ipaddress</span></code></a> 从字符串和整数创建对象。</p>
|
||||
<section id="a-note-on-ip-versions">
|
||||
<h3>关于IP版本的说明<a class="headerlink" href="#a-note-on-ip-versions" title="永久链接至标题">¶</a></h3>
|
||||
<p>对于不太熟悉 IP 寻址的读者,重要的是要知道 Internet 协议当前正在从协议的版本4转移到版本6。转换很大程度上是因为协议的版本4没有提供足够的地址来满足整个世界的需求,特别是考虑到越来越多的设备直接连接到互联网。</p>
|
||||
<p>解释协议的两个版本之间的差异的细节超出了本介绍的范围,但读者需要至少知道存在这两个版本,并且有时需要强制使用一个版本或其他版本。</p>
|
||||
</section>
|
||||
<section id="ip-host-addresses">
|
||||
<h3>IP主机地址<a class="headerlink" href="#ip-host-addresses" title="永久链接至标题">¶</a></h3>
|
||||
<p>通常称为“主机地址”的地址是使用IP寻址时最基本的单元。 创建地址的最简单方法是使用 <a class="reference internal" href="../library/ipaddress.html#ipaddress.ip_address" title="ipaddress.ip_address"><code class="xref py py-func docutils literal notranslate"><span class="pre">ipaddress.ip_address()</span></code></a> 工厂函数,该函数根据传入的值自动确定是创建 IPv4 还是 IPv6 地址:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s1">'192.0.2.1'</span><span class="p">)</span>
|
||||
<span class="go">IPv4Address('192.0.2.1')</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s1">'2001:DB8::1'</span><span class="p">)</span>
|
||||
<span class="go">IPv6Address('2001:db8::1')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>地址也可以直接从整数创建,适配32位的值并假定为IPv4地址:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="mi">3221225985</span><span class="p">)</span>
|
||||
<span class="go">IPv4Address('192.0.2.1')</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="mi">42540766411282592856903984951653826561</span><span class="p">)</span>
|
||||
<span class="go">IPv6Address('2001:db8::1')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>要强制使用IPv4或IPv6地址,可以直接调用相关的类。 这对于强制为小整数创建IPv6地址特别有用:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||||
<span class="go">IPv4Address('0.0.0.1')</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">IPv4Address</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||||
<span class="go">IPv4Address('0.0.0.1')</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">IPv6Address</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||||
<span class="go">IPv6Address('::1')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="defining-networks">
|
||||
<h3>定义网络<a class="headerlink" href="#defining-networks" title="永久链接至标题">¶</a></h3>
|
||||
<p>主机地址通常组合在一起形成IP网络,因此 <a class="reference internal" href="../library/ipaddress.html#module-ipaddress" title="ipaddress: IPv4/IPv6 manipulation library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ipaddress</span></code></a> 提供了一种创建、检查和操作网络定义的方法。 IP网络对象由字符串构成,这些字符串定义作为该网络一部分的主机地址范围。 该信息的最简单形式是“网络地址/网络前缀”对,其中前缀定义了比较的前导比特数,以确定地址是否是网络的一部分,并且网络地址定义了那些位的预期值。</p>
|
||||
<p>对于地址,提供了一个自动确定正确IP版本的工厂函数:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'192.0.2.0/24'</span><span class="p">)</span>
|
||||
<span class="go">IPv4Network('192.0.2.0/24')</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'2001:db8::0/96'</span><span class="p">)</span>
|
||||
<span class="go">IPv6Network('2001:db8::/96')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>网络对象不能设置任何主机位。 这样做的实际效果是``192.0.2.1/24``没有描述网络。 这种定义被称为接口对象,因为网络上IP表示法通常用于描述给定网络上的计算机的网络接口,并在下一节中进一步描述。</p>
|
||||
<p>默认情况下,尝试创建一个设置了主机位的网络对象将导致 <a class="reference internal" href="../library/exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ValueError</span></code></a> 被引发。 要请求将附加位强制为零,可以将标志``strict=False`` 传递给构造函数:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'192.0.2.1/24'</span><span class="p">)</span>
|
||||
<span class="gt">Traceback (most recent call last):</span>
|
||||
<span class="w"> </span><span class="c">...</span>
|
||||
<span class="gr">ValueError</span>: <span class="n">192.0.2.1/24 has host bits set</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'192.0.2.1/24'</span><span class="p">,</span> <span class="n">strict</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="go">IPv4Network('192.0.2.0/24')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>虽然字符串形式提供了更大的灵活性,但网络也可以用整数定义,就像主机地址一样。 在这种情况下,网络被认为只包含由整数标识的单个地址,因此网络前缀包括整个网络地址:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="mi">3221225984</span><span class="p">)</span>
|
||||
<span class="go">IPv4Network('192.0.2.0/32')</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="mi">42540766411282592856903984951653826560</span><span class="p">)</span>
|
||||
<span class="go">IPv6Network('2001:db8::/128')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>与地址一样,可以通过直接调用类构造函数而不是使用工厂函数来强制创建特定类型的网络。</p>
|
||||
</section>
|
||||
<section id="host-interfaces">
|
||||
<h3>主机接口<a class="headerlink" href="#host-interfaces" title="永久链接至标题">¶</a></h3>
|
||||
<p>如上所述,如果您需要描述特定网络上的地址,则地址和网络类都不够。 像 <code class="docutils literal notranslate"><span class="pre">192.0.2.1/24</span></code> 这样的表示法通常被网络工程师和为防火墙和路由器编写工具的人用作“ <code class="docutils literal notranslate"><span class="pre">192.0.2.0/24</span></code> 网络上的主机 <code class="docutils literal notranslate"><span class="pre">192.0.2.1</span></code> ”的简写。因此,<a class="reference internal" href="../library/ipaddress.html#module-ipaddress" title="ipaddress: IPv4/IPv6 manipulation library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ipaddress</span></code></a> 提供了一组将地址与特定网络相关联的混合类。用于创建的接口与用于定义网络对象的接口相同,除了地址部分不限于是网络地址。</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_interface</span><span class="p">(</span><span class="s1">'192.0.2.1/24'</span><span class="p">)</span>
|
||||
<span class="go">IPv4Interface('192.0.2.1/24')</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_interface</span><span class="p">(</span><span class="s1">'2001:db8::1/96'</span><span class="p">)</span>
|
||||
<span class="go">IPv6Interface('2001:db8::1/96')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>接受整数输入(与网络一样),并且可以通过直接调用相关构造函数来强制使用特定IP版本。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="inspecting-address-network-interface-objects">
|
||||
<h2>审查 Address/Network/Interface 对象<a class="headerlink" href="#inspecting-address-network-interface-objects" title="永久链接至标题">¶</a></h2>
|
||||
<p>你已经遇到了创建IPv(4|6)(Address|Network|Interface) 对象的麻烦,因此你可能希望获得有关它的信息。 <a class="reference internal" href="../library/ipaddress.html#module-ipaddress" title="ipaddress: IPv4/IPv6 manipulation library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ipaddress</span></code></a> 试图让这个过程变得简单直观。</p>
|
||||
<p>提取 IP 版本:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">addr4</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s1">'192.0.2.1'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">addr6</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s1">'2001:db8::1'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">addr6</span><span class="o">.</span><span class="n">version</span>
|
||||
<span class="go">6</span>
|
||||
<span class="gp">>>> </span><span class="n">addr4</span><span class="o">.</span><span class="n">version</span>
|
||||
<span class="go">4</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>从接口获取网络:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">host4</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_interface</span><span class="p">(</span><span class="s1">'192.0.2.1/24'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">host4</span><span class="o">.</span><span class="n">network</span>
|
||||
<span class="go">IPv4Network('192.0.2.0/24')</span>
|
||||
<span class="gp">>>> </span><span class="n">host6</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_interface</span><span class="p">(</span><span class="s1">'2001:db8::1/96'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">host6</span><span class="o">.</span><span class="n">network</span>
|
||||
<span class="go">IPv6Network('2001:db8::/96')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>找出网络中有多少独立地址:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">net4</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'192.0.2.0/24'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">net4</span><span class="o">.</span><span class="n">num_addresses</span>
|
||||
<span class="go">256</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'2001:db8::0/96'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span><span class="o">.</span><span class="n">num_addresses</span>
|
||||
<span class="go">4294967296</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>迭代网络上的“可用”地址:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">net4</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'192.0.2.0/24'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">net4</span><span class="o">.</span><span class="n">hosts</span><span class="p">():</span>
|
||||
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||||
<span class="go">192.0.2.1</span>
|
||||
<span class="go">192.0.2.2</span>
|
||||
<span class="go">192.0.2.3</span>
|
||||
<span class="go">192.0.2.4</span>
|
||||
<span class="go">...</span>
|
||||
<span class="go">192.0.2.252</span>
|
||||
<span class="go">192.0.2.253</span>
|
||||
<span class="go">192.0.2.254</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>获取网络掩码(即对应于网络前缀的设置位)或主机掩码(不属于网络掩码的任何位):</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">net4</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'192.0.2.0/24'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">net4</span><span class="o">.</span><span class="n">netmask</span>
|
||||
<span class="go">IPv4Address('255.255.255.0')</span>
|
||||
<span class="gp">>>> </span><span class="n">net4</span><span class="o">.</span><span class="n">hostmask</span>
|
||||
<span class="go">IPv4Address('0.0.0.255')</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'2001:db8::0/96'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span><span class="o">.</span><span class="n">netmask</span>
|
||||
<span class="go">IPv6Address('ffff:ffff:ffff:ffff:ffff:ffff::')</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span><span class="o">.</span><span class="n">hostmask</span>
|
||||
<span class="go">IPv6Address('::ffff:ffff')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>展开或压缩地址:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">addr6</span><span class="o">.</span><span class="n">exploded</span>
|
||||
<span class="go">'2001:0db8:0000:0000:0000:0000:0000:0001'</span>
|
||||
<span class="gp">>>> </span><span class="n">addr6</span><span class="o">.</span><span class="n">compressed</span>
|
||||
<span class="go">'2001:db8::1'</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span><span class="o">.</span><span class="n">exploded</span>
|
||||
<span class="go">'2001:0db8:0000:0000:0000:0000:0000:0000/96'</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span><span class="o">.</span><span class="n">compressed</span>
|
||||
<span class="go">'2001:db8::/96'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>虽然IPv4不支持展开或压缩,但关联对象仍提供相关属性,因此版本中性代码可以轻松确保最简洁或最详细的形式用于IPv6地址,同时仍能正确处理IPv4地址。</p>
|
||||
</section>
|
||||
<section id="networks-as-lists-of-addresses">
|
||||
<h2>Network 作为 Address 列表<a class="headerlink" href="#networks-as-lists-of-addresses" title="永久链接至标题">¶</a></h2>
|
||||
<p>将网络视为列表有时很有用。 这意味着它可以像这样索引它们:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">net4</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="go">IPv4Address('192.0.2.1')</span>
|
||||
<span class="gp">>>> </span><span class="n">net4</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="go">IPv4Address('192.0.2.255')</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="go">IPv6Address('2001:db8::1')</span>
|
||||
<span class="gp">>>> </span><span class="n">net6</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
|
||||
<span class="go">IPv6Address('2001:db8::ffff:ffff')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>它还意味着网络对象可以使用像这样的列表成员测试语法:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">address</span> <span class="ow">in</span> <span class="n">network</span><span class="p">:</span>
|
||||
<span class="c1"># do something</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>根据网络前缀有效地完成包含性测试:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">addr4</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s1">'192.0.2.1'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">addr4</span> <span class="ow">in</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'192.0.2.0/24'</span><span class="p">)</span>
|
||||
<span class="go">True</span>
|
||||
<span class="gp">>>> </span><span class="n">addr4</span> <span class="ow">in</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s1">'192.0.3.0/24'</span><span class="p">)</span>
|
||||
<span class="go">False</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="comparisons">
|
||||
<h2>比较运算<a class="headerlink" href="#comparisons" title="永久链接至标题">¶</a></h2>
|
||||
<p><a class="reference internal" href="../library/ipaddress.html#module-ipaddress" title="ipaddress: IPv4/IPv6 manipulation library."><code class="xref py py-mod docutils literal notranslate"><span class="pre">ipaddress</span></code></a> 有意义地提供了一些简单、希望直观的比较对象的方法:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s1">'192.0.2.1'</span><span class="p">)</span> <span class="o"><</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s1">'192.0.2.2'</span><span class="p">)</span>
|
||||
<span class="go">True</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如果你尝试比较不同版本或不同类型的对象,则会引发 <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>
|
||||
</section>
|
||||
<section id="using-ip-addresses-with-other-modules">
|
||||
<h2>将IP地址与其他模块一起使用<a class="headerlink" href="#using-ip-addresses-with-other-modules" title="永久链接至标题">¶</a></h2>
|
||||
<p>其他使用IP地址的模块(例如 <a class="reference internal" href="../library/socket.html#module-socket" title="socket: Low-level networking interface."><code class="xref py py-mod docutils literal notranslate"><span class="pre">socket</span></code></a> )通常不会直接接受来自该模块的对象。 相反,它们必须被强制转换为另一个模块可接受的整数或字符串:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">addr4</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s1">'192.0.2.1'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="nb">str</span><span class="p">(</span><span class="n">addr4</span><span class="p">)</span>
|
||||
<span class="go">'192.0.2.1'</span>
|
||||
<span class="gp">>>> </span><span class="nb">int</span><span class="p">(</span><span class="n">addr4</span><span class="p">)</span>
|
||||
<span class="go">3221225985</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="getting-more-detail-when-instance-creation-fails">
|
||||
<h2>实例创建失败时获取更多详细信息<a class="headerlink" href="#getting-more-detail-when-instance-creation-fails" title="永久链接至标题">¶</a></h2>
|
||||
<p>使用与版本无关的工厂函数创建 address/network/interface 对象时,任何错误都将报告为 <a class="reference internal" href="../library/exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ValueError</span></code></a> ,带有一般错误消息,只是说传入的值未被识别为该类型的对象。 缺少特定错误是因为有必要知道该值是*假设*是IPv4还是IPv6,以便提供有关其被拒绝原因的更多详细信息。</p>
|
||||
<p>为了支持访问这些额外细节的用例,各个类构造函数实际上引发了 <a class="reference internal" href="../library/exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ValueError</span></code></a> 子类 <a class="reference internal" href="../library/ipaddress.html#ipaddress.AddressValueError" title="ipaddress.AddressValueError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ipaddress.AddressValueError</span></code></a> 和 <a class="reference internal" href="../library/ipaddress.html#ipaddress.NetmaskValueError" title="ipaddress.NetmaskValueError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ipaddress.NetmaskValueError</span></code></a> 以准确指示定义的哪一部分无法正确解析。</p>
|
||||
<p>直接使用类构造函数时,错误消息更加详细。 例如:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_address</span><span class="p">(</span><span class="s2">"192.168.0.256"</span><span class="p">)</span>
|
||||
<span class="gt">Traceback (most recent call last):</span>
|
||||
<span class="w"> </span><span class="c">...</span>
|
||||
<span class="gr">ValueError</span>: <span class="n">'192.168.0.256' does not appear to be an IPv4 or IPv6 address</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">IPv4Address</span><span class="p">(</span><span class="s2">"192.168.0.256"</span><span class="p">)</span>
|
||||
<span class="gt">Traceback (most recent call last):</span>
|
||||
<span class="w"> </span><span class="c">...</span>
|
||||
<span class="gr">ipaddress.AddressValueError</span>: <span class="n">Octet 256 (> 255) not permitted in '192.168.0.256'</span>
|
||||
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">ip_network</span><span class="p">(</span><span class="s2">"192.168.0.1/64"</span><span class="p">)</span>
|
||||
<span class="gt">Traceback (most recent call last):</span>
|
||||
<span class="w"> </span><span class="c">...</span>
|
||||
<span class="gr">ValueError</span>: <span class="n">'192.168.0.1/64' does not appear to be an IPv4 or IPv6 network</span>
|
||||
<span class="gp">>>> </span><span class="n">ipaddress</span><span class="o">.</span><span class="n">IPv4Network</span><span class="p">(</span><span class="s2">"192.168.0.1/64"</span><span class="p">)</span>
|
||||
<span class="gt">Traceback (most recent call last):</span>
|
||||
<span class="w"> </span><span class="c">...</span>
|
||||
<span class="gr">ipaddress.NetmaskValueError</span>: <span class="n">'64' is not a valid netmask</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>但是,两个模块特定的异常都有 <a class="reference internal" href="../library/exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ValueError</span></code></a> 作为它们的父类,所以如果你不关心特定类型的错误,你仍然可以编写如下代码:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">network</span> <span class="o">=</span> <span class="n">ipaddress</span><span class="o">.</span><span class="n">IPv4Network</span><span class="p">(</span><span class="n">address</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="s1">'address/netmask is invalid for IPv4:'</span><span class="p">,</span> <span class="n">address</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</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="#">ipaddress模块介绍</a><ul>
|
||||
<li><a class="reference internal" href="#creating-address-network-interface-objects">创建 Address/Network/Interface 对象</a><ul>
|
||||
<li><a class="reference internal" href="#a-note-on-ip-versions">关于IP版本的说明</a></li>
|
||||
<li><a class="reference internal" href="#ip-host-addresses">IP主机地址</a></li>
|
||||
<li><a class="reference internal" href="#defining-networks">定义网络</a></li>
|
||||
<li><a class="reference internal" href="#host-interfaces">主机接口</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#inspecting-address-network-interface-objects">审查 Address/Network/Interface 对象</a></li>
|
||||
<li><a class="reference internal" href="#networks-as-lists-of-addresses">Network 作为 Address 列表</a></li>
|
||||
<li><a class="reference internal" href="#comparisons">比较运算</a></li>
|
||||
<li><a class="reference internal" href="#using-ip-addresses-with-other-modules">将IP地址与其他模块一起使用</a></li>
|
||||
<li><a class="reference internal" href="#getting-more-detail-when-instance-creation-fails">实例创建失败时获取更多详细信息</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="argparse.html"
|
||||
title="上一章">argparse 教程</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="clinic.html"
|
||||
title="下一章">Argument Clinic 的用法</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/howto/ipaddress.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="clinic.html" title="Argument Clinic 的用法"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="argparse.html" title="argparse 教程"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
2639
web/python-docs/howto/logging-cookbook.html
Normal file
2639
web/python-docs/howto/logging-cookbook.html
Normal file
File diff suppressed because it is too large
Load Diff
934
web/python-docs/howto/logging.html
Normal file
934
web/python-docs/howto/logging.html
Normal file
@@ -0,0 +1,934 @@
|
||||
|
||||
<!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>日志指南 — 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="日志专题手册" href="logging-cookbook.html" />
|
||||
<link rel="prev" title="函数式编程指引" href="functional.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/logging.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="#">日志指南</a><ul>
|
||||
<li><a class="reference internal" href="#basic-logging-tutorial">日志基础教程</a><ul>
|
||||
<li><a class="reference internal" href="#when-to-use-logging">什么时候使用日志</a></li>
|
||||
<li><a class="reference internal" href="#a-simple-example">一个简单的例子</a></li>
|
||||
<li><a class="reference internal" href="#logging-to-a-file">记录日志到文件</a></li>
|
||||
<li><a class="reference internal" href="#logging-from-multiple-modules">从多个模块记录日志</a></li>
|
||||
<li><a class="reference internal" href="#logging-variable-data">记录变量数据</a></li>
|
||||
<li><a class="reference internal" href="#changing-the-format-of-displayed-messages">更改显示消息的格式</a></li>
|
||||
<li><a class="reference internal" href="#displaying-the-date-time-in-messages">在消息中显示日期/时间</a></li>
|
||||
<li><a class="reference internal" href="#next-steps">后续步骤</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#advanced-logging-tutorial">进阶日志教程</a><ul>
|
||||
<li><a class="reference internal" href="#logging-flow">记录流程</a></li>
|
||||
<li><a class="reference internal" href="#loggers">记录器</a></li>
|
||||
<li><a class="reference internal" href="#handlers">处理器</a></li>
|
||||
<li><a class="reference internal" href="#formatters">格式器</a></li>
|
||||
<li><a class="reference internal" href="#configuring-logging">配置日志记录</a></li>
|
||||
<li><a class="reference internal" href="#what-happens-if-no-configuration-is-provided">如果没有提供配置会发生什么</a></li>
|
||||
<li><a class="reference internal" href="#configuring-logging-for-a-library">为库配置日志</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#logging-levels">日志级别</a><ul>
|
||||
<li><a class="reference internal" href="#custom-levels">自定义级别</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#useful-handlers">有用的处理器</a></li>
|
||||
<li><a class="reference internal" href="#exceptions-raised-during-logging">记录日志时引发的异常</a></li>
|
||||
<li><a class="reference internal" href="#using-arbitrary-objects-as-messages">使用任意对象作为消息</a></li>
|
||||
<li><a class="reference internal" href="#optimization">优化</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="functional.html"
|
||||
title="上一章">函数式编程指引</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="logging-cookbook.html"
|
||||
title="下一章">日志专题手册</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/howto/logging.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/howto/logging.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="logging-cookbook.html" title="日志专题手册"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="functional.html" title="函数式编程指引"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="logging-howto">
|
||||
<h1>日志指南<a class="headerlink" href="#logging-howto" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>Vinay Sajip <vinay_sajip at red-dove dot com></p>
|
||||
</dd>
|
||||
</dl>
|
||||
<section id="basic-logging-tutorial">
|
||||
<span id="logging-basic-tutorial"></span><h2>日志基础教程<a class="headerlink" href="#basic-logging-tutorial" title="永久链接至标题">¶</a></h2>
|
||||
<p>日志是对软件执行时所发生事件的一种追踪方式。软件开发人员对他们的代码添加日志调用,借此来指示某事件的发生。一个事件通过一些包含变量数据的描述信息来描述(比如:每个事件发生时的数据都是不同的)。开发者还会区分事件的重要性,重要性也被称为 <em>等级</em> 或 <em>严重性</em>。</p>
|
||||
<section id="when-to-use-logging">
|
||||
<h3>什么时候使用日志<a class="headerlink" href="#when-to-use-logging" title="永久链接至标题">¶</a></h3>
|
||||
<p>对于简单的日志使用来说日志功能提供了一系列便利的函数。它们是 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">debug()</span></code></a>,<a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">info()</span></code></a>,<a class="reference internal" href="../library/logging.html#logging.warning" title="logging.warning"><code class="xref py py-func docutils literal notranslate"><span class="pre">warning()</span></code></a>,<a class="reference internal" href="../library/logging.html#logging.error" title="logging.error"><code class="xref py py-func docutils literal notranslate"><span class="pre">error()</span></code></a> 和 <a class="reference internal" href="../library/logging.html#logging.critical" title="logging.critical"><code class="xref py py-func docutils literal notranslate"><span class="pre">critical()</span></code></a>。想要决定何时使用日志,请看下表,其中显示了对于每个通用任务集合来说最好的工具。</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 49%" />
|
||||
<col style="width: 51%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>你想要执行的任务</p></th>
|
||||
<th class="head"><p>此任务最好的工具</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p>对于命令行或程序的应用,结果显示在控制台。</p></td>
|
||||
<td><p><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></p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p>在对程序的普通操作发生时提交事件报告(比如:状态监控和错误调查)</p></td>
|
||||
<td><p><a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.info()</span></code></a> 函数(当有诊断目的需要详细输出信息时使用 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.debug()</span></code></a> 函数)</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p>提出一个警告信息基于一个特殊的运行时事件</p></td>
|
||||
<td><p><a class="reference internal" href="../library/warnings.html#warnings.warn" title="warnings.warn"><code class="xref py py-func docutils literal notranslate"><span class="pre">warnings.warn()</span></code></a> 位于代码库中,该事件是可以避免的,需要修改客户端应用以消除告警</p>
|
||||
<p><a class="reference internal" href="../library/logging.html#logging.warning" title="logging.warning"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.warning()</span></code></a> 不需要修改客户端应用,但是该事件还是需要引起关注</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p>对一个特殊的运行时事件报告错误</p></td>
|
||||
<td><p>引发异常</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p>报告错误而不引发异常(如在长时间运行中的服务端进程的错误处理)</p></td>
|
||||
<td><p><a class="reference internal" href="../library/logging.html#logging.error" title="logging.error"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.error()</span></code></a>, <a class="reference internal" href="../library/logging.html#logging.exception" title="logging.exception"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.exception()</span></code></a> 或 <a class="reference internal" href="../library/logging.html#logging.critical" title="logging.critical"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.critical()</span></code></a> 分别适用于特定的错误及应用领域</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>日志功能应以所追踪事件级别或严重性而定。各级别适用性如下(以严重性递增):</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 24%" />
|
||||
<col style="width: 76%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>级别</p></th>
|
||||
<th class="head"><p>何时使用</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">DEBUG</span></code></p></td>
|
||||
<td><p>细节信息,仅当诊断问题时适用。</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">INFO</span></code></p></td>
|
||||
<td><p>确认程序按预期运行。</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">WARNING</span></code></p></td>
|
||||
<td><p>表明有已经或即将发生的意外(例如:磁盘空间不足)。程序仍按预期进行。</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">ERROR</span></code></p></td>
|
||||
<td><p>由于严重的问题,程序的某些功能已经不能正常执行</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code></p></td>
|
||||
<td><p>严重的错误,表明程序已不能继续执行</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>默认的级别是 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code>,意味着只会追踪该级别及以上的事件,除非更改日志配置。</p>
|
||||
<p>所追踪事件可以以不同形式处理。最简单的方式是输出到控制台。另一种常用的方式是写入磁盘文件。</p>
|
||||
</section>
|
||||
<section id="a-simple-example">
|
||||
<span id="howto-minimal-example"></span><h3>一个简单的例子<a class="headerlink" href="#a-simple-example" title="永久链接至标题">¶</a></h3>
|
||||
<p>一个非常简单的例子:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">'Watch out!'</span><span class="p">)</span> <span class="c1"># will print a message to the console</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'I told you so'</span><span class="p">)</span> <span class="c1"># will not print anything</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如果你在命令行中输入这些代码并运行,你将会看到:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>WARNING:root:Watch out!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>输出到命令行。<code class="docutils literal notranslate"><span class="pre">INFO</span></code> 消息并没有出现,因为默认级别是 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> 。打印的信息包含事件的级别以及在日志调用中的对于事件的描述,例如 “Watch out!”。暂时不用担心 “root” 部分:之后会作出解释。输出格式可按需要进行调整,格式化选项同样会在之后作出解释。</p>
|
||||
</section>
|
||||
<section id="logging-to-a-file">
|
||||
<h3>记录日志到文件<a class="headerlink" href="#logging-to-a-file" title="永久链接至标题">¶</a></h3>
|
||||
<p>一种非常常见的情况是将日志事件记录到文件,让我们继续往下看。请确认启动新的Python 解释器,不要在上一个环境中继续操作:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">'example.log'</span><span class="p">,</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">'This message should go to the log file'</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'So should this'</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">'And this, too'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>现在,如果我们打开日志文件,我们应当能看到日志信息:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>DEBUG:root:This message should go to the log file
|
||||
INFO:root:So should this
|
||||
WARNING:root:And this, too
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>该示例同样展示了如何设置日志追踪级别的阈值。该示例中,由于我们设置的阈值是 <code class="docutils literal notranslate"><span class="pre">DEBUG</span></code>,所有信息都将被打印。</p>
|
||||
<p>如果你想从命令行设置日志级别,例如:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>--log=INFO
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>并且你将 <code class="docutils literal notranslate"><span class="pre">--log</span></code> 命令的参数存进了变量 <em>loglevel</em>,你可以用:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nb">getattr</span><span class="p">(</span><span class="n">logging</span><span class="p">,</span> <span class="n">loglevel</span><span class="o">.</span><span class="n">upper</span><span class="p">())</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>获取要通过 <em>level</em> 参数传给 <a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 的值。可如下对用户输入值进行错误检查:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># assuming loglevel is bound to the string value obtained from the</span>
|
||||
<span class="c1"># command line argument. Convert to upper case to allow the user to</span>
|
||||
<span class="c1"># specify --log=DEBUG or --log=debug</span>
|
||||
<span class="n">numeric_level</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">logging</span><span class="p">,</span> <span class="n">loglevel</span><span class="o">.</span><span class="n">upper</span><span class="p">(),</span> <span class="kc">None</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">numeric_level</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
|
||||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">'Invalid log level: </span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">loglevel</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">numeric_level</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>对 <a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 的调用应该在 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">debug()</span></code></a> , <a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">info()</span></code></a> 等的前面。因为它被设计为一次性的配置,只有第一次调用会进行操作,随后的调用不会产生有效操作。</p>
|
||||
<p>如果多次运行上述脚本,则连续运行的消息将追加到文件 <em>example.log</em> 。 如果你希望每次运行重新开始,而不是记住先前运行的消息,则可以通过将上例中的调用更改为来指定 <em>filemode</em> 参数:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">'example.log'</span><span class="p">,</span> <span class="n">filemode</span><span class="o">=</span><span class="s1">'w'</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>输出将与之前相同,但不再追加进日志文件,因此早期运行的消息将丢失。</p>
|
||||
</section>
|
||||
<section id="logging-from-multiple-modules">
|
||||
<h3>从多个模块记录日志<a class="headerlink" href="#logging-from-multiple-modules" title="永久链接至标题">¶</a></h3>
|
||||
<p>如果你的程序包含多个模块,这里有一个如何组织日志记录的示例:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># myapp.py</span>
|
||||
<span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="kn">import</span> <span class="nn">mylib</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">'myapp.log'</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'Started'</span><span class="p">)</span>
|
||||
<span class="n">mylib</span><span class="o">.</span><span class="n">do_something</span><span class="p">()</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'Finished'</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
|
||||
<span class="n">main</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># mylib.py</span>
|
||||
<span class="kn">import</span> <span class="nn">logging</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">do_something</span><span class="p">():</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'Doing something'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如果你运行 <em>myapp.py</em> ,你应该在 <em>myapp.log</em> 中看到:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>INFO:root:Started
|
||||
INFO:root:Doing something
|
||||
INFO:root:Finished
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这是你期待看到的。 你可以使用 <em>mylib.py</em> 中的模式将此概括为多个模块。 请注意,对于这种简单的使用模式,除了查看事件描述之外,你不能通过查看日志文件来了解应用程序中消息的 <em>来源</em> 。 如果要跟踪消息的位置,则需要参考教程级别以外的文档 —— 请参阅 <a class="reference internal" href="#logging-advanced-tutorial"><span class="std std-ref">进阶日志教程</span></a> 。</p>
|
||||
</section>
|
||||
<section id="logging-variable-data">
|
||||
<h3>记录变量数据<a class="headerlink" href="#logging-variable-data" title="永久链接至标题">¶</a></h3>
|
||||
<p>要记录变量数据,请使用格式字符串作为事件描述消息,并附加传入变量数据作为参数。 例如:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">'</span><span class="si">%s</span><span class="s1"> before you </span><span class="si">%s</span><span class="s1">'</span><span class="p">,</span> <span class="s1">'Look'</span><span class="p">,</span> <span class="s1">'leap!'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>将显示:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>WARNING:root:Look before you leap!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如你所见,将可变数据合并到事件描述消息中使用旧的 %-s形式的字符串格式化。 这是为了向后兼容:logging 包的出现时间早于较新的格式化选项例如 <a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.format()</span></code></a> 和 <a class="reference internal" href="../library/string.html#string.Template" title="string.Template"><code class="xref py py-class docutils literal notranslate"><span class="pre">string.Template</span></code></a>。 这些较新格式化选项 <em>是</em> 受支持的,但探索它们超出了本教程的范围:有关详细信息,请参阅 <a class="reference internal" href="logging-cookbook.html#formatting-styles"><span class="std std-ref">生效于整个应用程序的格式化样式</span></a>。</p>
|
||||
</section>
|
||||
<section id="changing-the-format-of-displayed-messages">
|
||||
<h3>更改显示消息的格式<a class="headerlink" href="#changing-the-format-of-displayed-messages" title="永久链接至标题">¶</a></h3>
|
||||
<p>要更改用于显示消息的格式,你需要指定要使用的格式:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="nb">format</span><span class="o">=</span><span class="s1">'</span><span class="si">%(levelname)s</span><span class="s1">:</span><span class="si">%(message)s</span><span class="s1">'</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">'This message should appear on the console'</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'So should this'</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">'And this, too'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这将输出:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>DEBUG:This message should appear on the console
|
||||
INFO:So should this
|
||||
WARNING:And this, too
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>注意在前面例子中出现的 “root” 已消失。文档 <a class="reference internal" href="../library/logging.html#logrecord-attributes"><span class="std std-ref">LogRecord 属性</span></a> 列出了可在格式字符串中出现的所有内容,但在简单的使用场景中,你只需要 <em>levelname</em> (严重性)、<em>message</em> (事件描述,包含可变的数据)或许再加上事件发生的时间。 这将在下一节中介绍。</p>
|
||||
</section>
|
||||
<section id="displaying-the-date-time-in-messages">
|
||||
<h3>在消息中显示日期/时间<a class="headerlink" href="#displaying-the-date-time-in-messages" title="永久链接至标题">¶</a></h3>
|
||||
<p>要显示事件的日期和时间,你可以在格式字符串中放置 '%(asctime)s'</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="nb">format</span><span class="o">=</span><span class="s1">'</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">'</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">'is when this event was logged.'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>应该打印这样的东西:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>2010-12-12 11:41:42,612 is when this event was logged.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>日期/时间显示的默认格式(如上所示)类似于 ISO8601 或 <span class="target" id="index-2"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc3339.html"><strong>RFC 3339</strong></a> 。 如果你需要更多地控制日期/时间的格式,请为 <code class="docutils literal notranslate"><span class="pre">basicConfig</span></code> 提供 <em>datefmt</em> 参数,如下例所示:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">basicConfig</span><span class="p">(</span><span class="nb">format</span><span class="o">=</span><span class="s1">'</span><span class="si">%(asctime)s</span><span class="s1"> </span><span class="si">%(message)s</span><span class="s1">'</span><span class="p">,</span> <span class="n">datefmt</span><span class="o">=</span><span class="s1">'%m/</span><span class="si">%d</span><span class="s1">/%Y %I:%M:%S %p'</span><span class="p">)</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">'is when this event was logged.'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这会显示如下内容:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>12/12/2010 11:46:36 AM is when this event was logged.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><em>datefmt</em> 参数的格式与 <a class="reference internal" href="../library/time.html#time.strftime" title="time.strftime"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.strftime()</span></code></a> 支持的格式相同。</p>
|
||||
</section>
|
||||
<section id="next-steps">
|
||||
<h3>后续步骤<a class="headerlink" href="#next-steps" title="永久链接至标题">¶</a></h3>
|
||||
<p>基本教程到此结束。 它应该足以让你启动并运行日志记录。 logging 包提供了更多功能,但为了充分利用它,你需要花更多的时间来阅读以下部分。 如果你准备好了,可以拿一些你最喜欢的饮料然后继续。</p>
|
||||
<p>如果你的日志记录需求很简单,那么使用上面的示例将日志记录合并到你自己的脚本中,如果你遇到问题或者不理解某些内容,请在 comp.lang.python Usenet 组上发布一个问题(在 <a class="reference external" href="https://groups.google.com/forum/#!forum/comp.lang.python">https://groups.google.com/forum/#!forum/comp.lang.python</a> ) ,你将在短时间内得到帮助。</p>
|
||||
<p>还不够? 你可以继续阅读接下来的几个部分,这些部分提供了比上面基本部分更高级或深入的教程。 之后,你可以看一下 <a class="reference internal" href="logging-cookbook.html#logging-cookbook"><span class="std std-ref">日志专题手册</span></a> 。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="advanced-logging-tutorial">
|
||||
<span id="logging-advanced-tutorial"></span><h2>进阶日志教程<a class="headerlink" href="#advanced-logging-tutorial" title="永久链接至标题">¶</a></h2>
|
||||
<p>日志库采用模块化方法,并提供几类组件:记录器、处理器、过滤器和格式器。</p>
|
||||
<ul class="simple">
|
||||
<li><p>记录器暴露了应用程序代码直接使用的接口。</p></li>
|
||||
<li><p>处理器将日志记录(由记录器创建)发送到适当的目标。</p></li>
|
||||
<li><p>过滤器提供了更细粒度的功能,用于确定要输出的日志记录。</p></li>
|
||||
<li><p>格式器指定最终输出中日志记录的样式。</p></li>
|
||||
</ul>
|
||||
<p>日志事件信息在 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 实例中的记录器、处理器、过滤器和格式器之间传递。</p>
|
||||
<p>通过调用 <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a> 类(以下称为 <em class="dfn">loggers</em> , 记录器)的实例来执行日志记录。 每个实例都有一个名称,它们在概念上以点(句点)作为分隔符排列在命名空间的层次结构中。 例如,名为 'scan' 的记录器是记录器 'scan.text' ,'scan.html' 和 'scan.pdf' 的父级。 记录器名称可以是你想要的任何名称,并指示记录消息源自的应用程序区域。</p>
|
||||
<p>在命名记录器时使用的一个好习惯是在每个使用日志记录的模块中使用模块级记录器,命名如下:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这意味着记录器名称跟踪包或模块的层次结构,并且直观地从记录器名称显示记录事件的位置。</p>
|
||||
<p>记录器层次结构的根称为根记录器。 这是函数 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">debug()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">info()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.warning" title="logging.warning"><code class="xref py py-func docutils literal notranslate"><span class="pre">warning()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.error" title="logging.error"><code class="xref py py-func docutils literal notranslate"><span class="pre">error()</span></code></a> 和 <a class="reference internal" href="../library/logging.html#logging.critical" title="logging.critical"><code class="xref py py-func docutils literal notranslate"><span class="pre">critical()</span></code></a> 使用的记录器,它们就是调用了根记录器的同名方法。 函数和方法具有相同的签名。 根记录器的名称在输出中打印为 'root' 。</p>
|
||||
<p>当然,可以将消息记录到不同的地方。 软件包中的支持包含,用于将日志消息写入文件、 HTTP GET/POST 位置、通过 SMTP 发送电子邮件、通用套接字、队列或特定于操作系统的日志记录机制(如 syslog 或 Windows NT 事件日志)。 目标由 <em class="dfn">handler</em> 类提供。 如果你有任何内置处理器类未满足的特殊要求,则可以创建自己的日志目标类。</p>
|
||||
<p>默认情况下,没有为任何日志消息设置目标。 你可以使用 <a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 指定目标(例如控制台或文件),如教程示例中所示。 如果你调用函数 <a class="reference internal" href="../library/logging.html#logging.debug" title="logging.debug"><code class="xref py py-func docutils literal notranslate"><span class="pre">debug()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.info" title="logging.info"><code class="xref py py-func docutils literal notranslate"><span class="pre">info()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.warning" title="logging.warning"><code class="xref py py-func docutils literal notranslate"><span class="pre">warning()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.error" title="logging.error"><code class="xref py py-func docutils literal notranslate"><span class="pre">error()</span></code></a> 和 <a class="reference internal" href="../library/logging.html#logging.critical" title="logging.critical"><code class="xref py py-func docutils literal notranslate"><span class="pre">critical()</span></code></a> ,它们将检查是否有设置目标;如果没有设置,将在委托给根记录器进行实际的消息输出之前设置目标为控制台( <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> )并设置显示消息的默认格式。</p>
|
||||
<p>由 <a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 设置的消息默认格式为:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>severity:logger name:message
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>你可以通过使用 <em>format</em> 参数将格式字符串传递给 <a class="reference internal" href="../library/logging.html#logging.basicConfig" title="logging.basicConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">basicConfig()</span></code></a> 来更改此设置。有关如何构造格式字符串的所有选项,请参阅 <a class="reference internal" href="../library/logging.html#formatter-objects"><span class="std std-ref">格式器对象</span></a> 。</p>
|
||||
<section id="logging-flow">
|
||||
<h3>记录流程<a class="headerlink" href="#logging-flow" title="永久链接至标题">¶</a></h3>
|
||||
<p>记录器和处理器中的日志事件信息流程如下图所示。</p>
|
||||
<img alt="../_images/logging_flow.png" src="../_images/logging_flow.png" />
|
||||
</section>
|
||||
<section id="loggers">
|
||||
<h3>记录器<a class="headerlink" href="#loggers" title="永久链接至标题">¶</a></h3>
|
||||
<p><a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a> 对象有三重任务。首先,它们向应用程序代码公开了几种方法,以便应用程序可以在运行时记录消息。其次,记录器对象根据严重性(默认过滤工具)或过滤器对象确定要处理的日志消息。第三,记录器对象将相关的日志消息传递给所有感兴趣的日志处理器。</p>
|
||||
<p>记录器对象上使用最广泛的方法分为两类:配置和消息发送。</p>
|
||||
<p>这些是最常见的配置方法:</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.setLevel" title="logging.Logger.setLevel"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.setLevel()</span></code></a> 指定记录器将处理的最低严重性日志消息,其中 debug 是最低内置严重性级别, critical 是最高内置严重性级别。 例如,如果严重性级别为 INFO ,则记录器将仅处理 INFO 、 WARNING 、 ERROR 和 CRITICAL 消息,并将忽略 DEBUG 消息。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.addHandler()</span></code></a> 和 <a class="reference internal" href="../library/logging.html#logging.Logger.removeHandler" title="logging.Logger.removeHandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.removeHandler()</span></code></a> 从记录器对象中添加和删除处理器对象。处理器在以下内容中有更详细的介绍 <a class="reference internal" href="#handler-basic"><span class="std std-ref">处理器</span></a> 。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.addFilter" title="logging.Logger.addFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.addFilter()</span></code></a> 和 <a class="reference internal" href="../library/logging.html#logging.Logger.removeFilter" title="logging.Logger.removeFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.removeFilter()</span></code></a> 可以添加或移除记录器对象中的过滤器。 <a class="reference internal" href="../library/logging.html#filter"><span class="std std-ref">过滤器对象</span></a> 包含更多的过滤器细节。</p></li>
|
||||
</ul>
|
||||
<p>你不需要总是在你创建的每个记录器上都调用这些方法。 请参阅本节的最后两段。</p>
|
||||
<p>配置记录器对象后,以下方法将创建日志消息:</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.debug" title="logging.Logger.debug"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.debug()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.Logger.info" title="logging.Logger.info"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.info()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.Logger.warning" title="logging.Logger.warning"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.warning()</span></code></a> 、 <a class="reference internal" href="../library/logging.html#logging.Logger.error" title="logging.Logger.error"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.error()</span></code></a> 和 <a class="reference internal" href="../library/logging.html#logging.Logger.critical" title="logging.Logger.critical"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.critical()</span></code></a> 都创建日志记录,包含消息和与其各自方法名称对应的级别。该消息实际上是一个格式化字符串,它可能包含标题字符串替换语法 <code class="docutils literal notranslate"><span class="pre">%s</span></code> 、 <code class="docutils literal notranslate"><span class="pre">%d</span></code> 、 <code class="docutils literal notranslate"><span class="pre">%f</span></code> 等等。其余参数是与消息中的替换字段对应的对象列表。关于 <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> ,日志记录方法只关注 <code class="docutils literal notranslate"><span class="pre">exc_info</span></code> 的关键字,并用它来确定是否记录异常信息。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.exception" title="logging.Logger.exception"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.exception()</span></code></a> 创建与 <a class="reference internal" href="../library/logging.html#logging.Logger.error" title="logging.Logger.error"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.error()</span></code></a> 相似的日志信息。 不同之处是, <a class="reference internal" href="../library/logging.html#logging.Logger.exception" title="logging.Logger.exception"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.exception()</span></code></a> 同时还记录当前的堆栈追踪。仅从异常处理程序调用此方法。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.html#logging.Logger.log" title="logging.Logger.log"><code class="xref py py-meth docutils literal notranslate"><span class="pre">Logger.log()</span></code></a> 将日志级别作为显式参数。对于记录消息而言,这比使用上面列出的日志级别便利方法更加冗长,但这是使用自定义日志级别的方法。</p></li>
|
||||
</ul>
|
||||
<p><a class="reference internal" href="../library/logging.html#logging.getLogger" title="logging.getLogger"><code class="xref py py-func docutils literal notranslate"><span class="pre">getLogger()</span></code></a> 返回对具有指定名称的记录器实例的引用(如果已提供),或者如果没有则返回 <code class="docutils literal notranslate"><span class="pre">root</span></code> 。名称是以句点分隔的层次结构。多次调用 <a class="reference internal" href="../library/logging.html#logging.getLogger" title="logging.getLogger"><code class="xref py py-func docutils literal notranslate"><span class="pre">getLogger()</span></code></a> 具有相同的名称将返回对同一记录器对象的引用。在分层列表中较低的记录器是列表中较高的记录器的子项。例如,给定一个名为 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 的记录器,名称为 <code class="docutils literal notranslate"><span class="pre">foo.bar</span></code> 、 <code class="docutils literal notranslate"><span class="pre">foo.bar.baz</span></code> 和 <code class="docutils literal notranslate"><span class="pre">foo.bam</span></code> 的记录器都是 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 子项。</p>
|
||||
<p>记录器具有 <em>有效等级</em> 的概念。如果未在记录器上显式设置级别,则使用其父记录器的级别作为其有效级别。如果父记录器没有明确的级别设置,则检查 <em>其</em> 父级。依此类推,搜索所有上级元素,直到找到明确设置的级别。根记录器始终具有明确的级别配置(默认情况下为 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> )。在决定是否处理事件时,记录器的有效级别用于确定事件是否传递给记录器相关的处理器。</p>
|
||||
<p>子记录器将消息传播到与其父级记录器关联的处理器。因此,不必为应用程序使用的所有记录器定义和配置处理器。一般为顶级记录器配置处理器,再根据需要创建子记录器就足够了。(但是,你可以通过将记录器的 <em>propagate</em> 属性设置为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 来关闭传播。)</p>
|
||||
</section>
|
||||
<section id="handlers">
|
||||
<span id="handler-basic"></span><h3>处理器<a class="headerlink" href="#handlers" title="永久链接至标题">¶</a></h3>
|
||||
<p><a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 对象负责将适当的日志消息(基于日志消息的严重性)分派给处理器的指定目标。 <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a> 对象可以使用 <a class="reference internal" href="../library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addHandler()</span></code></a> 方法向自己添加零个或多个处理器对象。作为示例场景,应用程序可能希望将所有日志消息发送到日志文件,将错误或更高的所有日志消息发送到标准输出,以及将所有关键消息发送至一个邮件地址。 此方案需要三个单独的处理器,其中每个处理器负责将特定严重性的消息发送到特定位置。</p>
|
||||
<p>标准库包含很多处理器类型(参见 <a class="reference internal" href="#useful-handlers"><span class="std std-ref">有用的处理器</span></a> );教程主要使用 <a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a> 和 <a class="reference internal" href="../library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">FileHandler</span></code></a> 。</p>
|
||||
<p>处理器中很少有方法可供应用程序开发人员使用。使用内置处理器对象(即不创建自定义处理器)的应用程序开发人员能用到的仅有以下配置方法:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="xref py py-meth docutils literal notranslate"><span class="pre">setLevel()</span></code> 方法,就像在记录器对象中一样,指定将被分派到适当目标的最低严重性。为什么有两个 <code class="xref py py-func docutils literal notranslate"><span class="pre">setLevel()</span></code> 方法?记录器中设置的级别确定将传递给其处理器的消息的严重性。每个处理器中设置的级别确定该处理器将发送哪些消息。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.html#logging.Handler.setFormatter" title="logging.Handler.setFormatter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">setFormatter()</span></code></a> 选择一个该处理器使用的 Formatter 对象。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.html#logging.Handler.addFilter" title="logging.Handler.addFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addFilter()</span></code></a> 和 <a class="reference internal" href="../library/logging.html#logging.Handler.removeFilter" title="logging.Handler.removeFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">removeFilter()</span></code></a> 分别在处理器上配置和取消配置过滤器对象。</p></li>
|
||||
</ul>
|
||||
<p>应用程序代码不应直接实例化并使用 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 的实例。 相反, <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 类是一个基类,它定义了所有处理器应该具有的接口,并建立了子类可以使用(或覆盖)的一些默认行为。</p>
|
||||
</section>
|
||||
<section id="formatters">
|
||||
<h3>格式器<a class="headerlink" href="#formatters" title="永久链接至标题">¶</a></h3>
|
||||
<p>格式化器对象配置日志消息的最终顺序、结构和内容。 与 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">logging.Handler</span></code></a> 类不同,应用程序代码可以实例化格式器类,但如果应用程序需要特殊行为,则可能会对格式化器进行子类化定制。构造函数有三个可选参数 —— 消息格式字符串、日期格式字符串和样式指示符。</p>
|
||||
<dl class="method">
|
||||
<dt id="logging.logging.Formatter.__init__">
|
||||
<code class="sig-prename descclassname">logging.Formatter.</code><code class="sig-name descname">__init__</code><span class="sig-paren">(</span><em class="sig-param">fmt=None</em>, <em class="sig-param">datefmt=None</em>, <em class="sig-param">style='%'</em><span class="sig-paren">)</span><a class="headerlink" href="#logging.logging.Formatter.__init__" title="永久链接至目标">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<p>如果没有消息格式字符串,则默认使用原始消息。如果没有日期格式字符串,则默认日期格式为:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>%Y-%m-%d %H:%M:%S
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>最后加上毫秒数。 <code class="docutils literal notranslate"><span class="pre">style</span></code> 是 <cite>%</cite>,'{ ' 或 '$' 之一。 如果未指定,则将使用 '%'。</p>
|
||||
<p>如果 <code class="docutils literal notranslate"><span class="pre">style</span></code> 是 '%',则消息格式字符串使用 <code class="docutils literal notranslate"><span class="pre">%(<dictionary</span> <span class="pre">key>)s</span></code> 样式字符串替换;可能的键值在 <a class="reference internal" href="../library/logging.html#logrecord-attributes"><span class="std std-ref">LogRecord 属性</span></a> 中。 如果样式为 '{',则假定消息格式字符串与 <a class="reference internal" href="../library/stdtypes.html#str.format" title="str.format"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.format()</span></code></a> (使用关键字参数)兼容,而如果样式为 '$' ,则消息格式字符串应符合 <a class="reference internal" href="../library/string.html#string.Template.substitute" title="string.Template.substitute"><code class="xref py py-meth docutils literal notranslate"><span class="pre">string.Template.substitute()</span></code></a> 。</p>
|
||||
<div class="versionchanged">
|
||||
<p><span class="versionmodified changed">在 3.2 版更改: </span>添加 <code class="docutils literal notranslate"><span class="pre">style</span></code> 形参。</p>
|
||||
</div>
|
||||
<p>以下消息格式字符串将以人类可读的格式记录时间、消息的严重性以及消息的内容,按此顺序:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="s1">'</span><span class="si">%(asctime)s</span><span class="s1"> - </span><span class="si">%(levelname)s</span><span class="s1"> - </span><span class="si">%(message)s</span><span class="s1">'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>格式器通过用户可配置的函数将记录的创建时间转换为元组。 默认情况下,使用 <a class="reference internal" href="../library/time.html#time.localtime" title="time.localtime"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.localtime()</span></code></a> ;要为特定格式器实例更改此项,请将实例的 <code class="docutils literal notranslate"><span class="pre">converter</span></code> 属性设置为与 <a class="reference internal" href="../library/time.html#time.localtime" title="time.localtime"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.localtime()</span></code></a> 或 <a class="reference internal" href="../library/time.html#time.gmtime" title="time.gmtime"><code class="xref py py-func docutils literal notranslate"><span class="pre">time.gmtime()</span></code></a> 具有相同签名的函数。 要为所有格式器更改它,例如,如果你希望所有记录时间都以 GMT 显示,请在格式器类中设置 <code class="docutils literal notranslate"><span class="pre">converter</span></code> 属性(对于 GMT 显示,设置为 <code class="docutils literal notranslate"><span class="pre">time.gmtime</span></code> )。</p>
|
||||
</section>
|
||||
<section id="configuring-logging">
|
||||
<h3>配置日志记录<a class="headerlink" href="#configuring-logging" title="永久链接至标题">¶</a></h3>
|
||||
<p>开发者可以通过三种方式配置日志记录:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>使用调用上面列出的配置方法的 Python 代码显式创建记录器、处理器和格式器。</p></li>
|
||||
<li><p>创建日志配置文件并使用 <a class="reference internal" href="../library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">fileConfig()</span></code></a> 函数读取它。</p></li>
|
||||
<li><p>创建配置信息字典并将其传递给 <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">dictConfig()</span></code></a> 函数。</p></li>
|
||||
</ol>
|
||||
<p>有关最后两个选项的参考文档,请参阅 <a class="reference internal" href="../library/logging.config.html#logging-config-api"><span class="std std-ref">配置函数</span></a> 。 以下示例使用 Python 代码配置一个非常简单的记录器、一个控制台处理器和一个简单的格式器:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
|
||||
<span class="c1"># create logger</span>
|
||||
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">'simple_example'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># create console handler and set level to debug</span>
|
||||
<span class="n">ch</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">()</span>
|
||||
<span class="n">ch</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># create formatter</span>
|
||||
<span class="n">formatter</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s1">'</span><span class="si">%(asctime)s</span><span class="s1"> - </span><span class="si">%(name)s</span><span class="s1"> - </span><span class="si">%(levelname)s</span><span class="s1"> - </span><span class="si">%(message)s</span><span class="s1">'</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># add formatter to ch</span>
|
||||
<span class="n">ch</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">formatter</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># add ch to logger</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">ch</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># 'application' code</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">'debug message'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'info message'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">'warn message'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">'error message'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">'critical message'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>从命令行运行此模块将生成以下输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python<span class="w"> </span>simple_logging_module.py
|
||||
<span class="go">2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message</span>
|
||||
<span class="go">2005-03-19 15:10:26,620 - simple_example - INFO - info message</span>
|
||||
<span class="go">2005-03-19 15:10:26,695 - simple_example - WARNING - warn message</span>
|
||||
<span class="go">2005-03-19 15:10:26,697 - simple_example - ERROR - error message</span>
|
||||
<span class="go">2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>以下 Python 模块创建的记录器、处理器和格式器几乎与上面列出的示例中的相同,唯一的区别是对象的名称:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="kn">import</span> <span class="nn">logging.config</span>
|
||||
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">fileConfig</span><span class="p">(</span><span class="s1">'logging.conf'</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># create logger</span>
|
||||
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">'simpleExample'</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># 'application' code</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">'debug message'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'info message'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">'warn message'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">'error message'</span><span class="p">)</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">critical</span><span class="p">(</span><span class="s1">'critical message'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这是 logging.conf 文件:</p>
|
||||
<div class="highlight-ini notranslate"><div class="highlight"><pre><span></span><span class="k">[loggers]</span>
|
||||
<span class="na">keys</span><span class="o">=</span><span class="s">root,simpleExample</span>
|
||||
|
||||
<span class="k">[handlers]</span>
|
||||
<span class="na">keys</span><span class="o">=</span><span class="s">consoleHandler</span>
|
||||
|
||||
<span class="k">[formatters]</span>
|
||||
<span class="na">keys</span><span class="o">=</span><span class="s">simpleFormatter</span>
|
||||
|
||||
<span class="k">[logger_root]</span>
|
||||
<span class="na">level</span><span class="o">=</span><span class="s">DEBUG</span>
|
||||
<span class="na">handlers</span><span class="o">=</span><span class="s">consoleHandler</span>
|
||||
|
||||
<span class="k">[logger_simpleExample]</span>
|
||||
<span class="na">level</span><span class="o">=</span><span class="s">DEBUG</span>
|
||||
<span class="na">handlers</span><span class="o">=</span><span class="s">consoleHandler</span>
|
||||
<span class="na">qualname</span><span class="o">=</span><span class="s">simpleExample</span>
|
||||
<span class="na">propagate</span><span class="o">=</span><span class="s">0</span>
|
||||
|
||||
<span class="k">[handler_consoleHandler]</span>
|
||||
<span class="na">class</span><span class="o">=</span><span class="s">StreamHandler</span>
|
||||
<span class="na">level</span><span class="o">=</span><span class="s">DEBUG</span>
|
||||
<span class="na">formatter</span><span class="o">=</span><span class="s">simpleFormatter</span>
|
||||
<span class="na">args</span><span class="o">=</span><span class="s">(sys.stdout,)</span>
|
||||
|
||||
<span class="k">[formatter_simpleFormatter]</span>
|
||||
<span class="na">format</span><span class="o">=</span><span class="s">%(asctime)s - %(name)s - %(levelname)s - %(message)s</span>
|
||||
<span class="na">datefmt</span><span class="o">=</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>其输出与不基于配置文件的示例几乎相同:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python<span class="w"> </span>simple_logging_config.py
|
||||
<span class="go">2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message</span>
|
||||
<span class="go">2005-03-19 15:38:55,979 - simpleExample - INFO - info message</span>
|
||||
<span class="go">2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message</span>
|
||||
<span class="go">2005-03-19 15:38:56,055 - simpleExample - ERROR - error message</span>
|
||||
<span class="go">2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>你可以看到配置文件方法相较于 Python 代码方法有一些优势,主要是配置和代码的分离以及非开发者轻松修改日志记录属性的能力。</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">警告</p>
|
||||
<p><a class="reference internal" href="../library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">fileConfig()</span></code></a> 函数接受一个默认参数 <code class="docutils literal notranslate"><span class="pre">disable_existing_loggers</span></code> ,出于向后兼容的原因,默认为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。这可能与您的期望不同,因为除非在配置中明确命名它们(或其父级),否则它将导致在 <a class="reference internal" href="../library/logging.config.html#logging.config.fileConfig" title="logging.config.fileConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">fileConfig()</span></code></a> 调用之前存在的任何非 root 记录器被禁用。有关更多信息,请参阅参考文档,如果需要,请将此参数指定为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 。</p>
|
||||
<p>传递给 <a class="reference internal" href="../library/logging.config.html#logging.config.dictConfig" title="logging.config.dictConfig"><code class="xref py py-func docutils literal notranslate"><span class="pre">dictConfig()</span></code></a> 的字典也可以用键 <code class="docutils literal notranslate"><span class="pre">disable_existing_loggers</span></code> 指定一个布尔值,如果没有在字典中明确指定,也默认被解释为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。这会导致上面描述的记录器禁用行为,这可能与你的期望不同——在这种情况下,请明确地为其提供 <code class="docutils literal notranslate"><span class="pre">False</span></code> 值。</p>
|
||||
</div>
|
||||
<p>请注意,配置文件中引用的类名称需要相对于日志记录模块,或者可以使用常规导入机制解析的绝对值。因此,你可以使用 <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.WatchedFileHandler" title="logging.handlers.WatchedFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">WatchedFileHandler</span></code></a> (相对于日志记录模块)或 <code class="docutils literal notranslate"><span class="pre">mypackage.mymodule.MyHandler</span></code> (对于在 <code class="docutils literal notranslate"><span class="pre">mypackage</span></code> 包中定义的类和模块 <code class="docutils literal notranslate"><span class="pre">mymodule</span></code> ,其中 <code class="docutils literal notranslate"><span class="pre">mypackage</span></code> 在 Python 导入路径上可用)。</p>
|
||||
<p>在 Python 3.2 中,引入了一种新的配置日志记录的方法,使用字典来保存配置信息。 这提供了上述基于配置文件方法的功能的超集,并且是新应用程序和部署的推荐配置方法。 因为 Python 字典用于保存配置信息,并且由于你可以使用不同的方式填充该字典,因此你有更多的配置选项。 例如,你可以使用 JSON 格式的配置文件,或者如果你有权访问 YAML 处理功能,则可以使用 YAML 格式的文件来填充配置字典。当然,你可以在 Python 代码中构造字典,通过套接字以 pickle 形式接收它,或者使用对你的应用程序合理的任何方法。</p>
|
||||
<p>以下是与上述相同配置的示例,采用 YAML 格式,用于新的基于字典的方法:</p>
|
||||
<div class="highlight-yaml notranslate"><div class="highlight"><pre><span></span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">1</span>
|
||||
<span class="nt">formatters</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="nt">simple</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="nt">format</span><span class="p">:</span><span class="w"> </span><span class="s">'%(asctime)s</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">%(name)s</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">%(levelname)s</span><span class="nv"> </span><span class="s">-</span><span class="nv"> </span><span class="s">%(message)s'</span>
|
||||
<span class="nt">handlers</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="nt">console</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="nt">class</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">logging.StreamHandler</span>
|
||||
<span class="w"> </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">DEBUG</span>
|
||||
<span class="w"> </span><span class="nt">formatter</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">simple</span>
|
||||
<span class="w"> </span><span class="nt">stream</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ext://sys.stdout</span>
|
||||
<span class="nt">loggers</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="nt">simpleExample</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">DEBUG</span>
|
||||
<span class="w"> </span><span class="nt">handlers</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">console</span><span class="p p-Indicator">]</span>
|
||||
<span class="w"> </span><span class="nt">propagate</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">no</span>
|
||||
<span class="nt">root</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">DEBUG</span>
|
||||
<span class="w"> </span><span class="nt">handlers</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">console</span><span class="p p-Indicator">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>有关使用字典进行日志记录的更多信息,请参阅 <a class="reference internal" href="../library/logging.config.html#logging-config-api"><span class="std std-ref">配置函数</span></a>。</p>
|
||||
</section>
|
||||
<section id="what-happens-if-no-configuration-is-provided">
|
||||
<h3>如果没有提供配置会发生什么<a class="headerlink" href="#what-happens-if-no-configuration-is-provided" title="永久链接至标题">¶</a></h3>
|
||||
<p>如果未提供日志记录配置,则可能出现需要输出日志记录事件但无法找到输出事件的处理器的情况。 在这些情况下,logging 包的行为取决于 Python 版本。</p>
|
||||
<p>对于 3.2 之前的 Python 版本,行为如下:</p>
|
||||
<ul class="simple">
|
||||
<li><p>如果 <em>logging.raiseExceptions</em> 为 <code class="docutils literal notranslate"><span class="pre">False</span></code> (生产模式),则会以静默方式丢弃该事件。</p></li>
|
||||
<li><p>如果 <em>logging.raiseExceptions</em> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> (开发模式),则会打印一条消息 'No handlers could be found for logger X.Y.Z'。</p></li>
|
||||
</ul>
|
||||
<p>在 Python 3.2 及更高版本中,行为如下:</p>
|
||||
<ul class="simple">
|
||||
<li><p>事件使用 “最后的处理器” 输出,存储在 <code class="docutils literal notranslate"><span class="pre">logging.lastResort</span></code> 中。 这个内部处理器与任何记录器都没有关联,它的作用类似于 <a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a> ,它将事件描述消息写入 <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> 的当前值(因此服从任何可能的重定向影响)。 没有对消息进行格式化——只打印裸事件描述消息。处理器的级别设置为 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code>,因此将输出此级别和更高级别的所有事件。</p></li>
|
||||
</ul>
|
||||
<p>要获得 3.2 之前的行为,可以设置 <code class="docutils literal notranslate"><span class="pre">logging.lastResort</span></code> 为 <code class="docutils literal notranslate"><span class="pre">None</span></code>。</p>
|
||||
</section>
|
||||
<section id="configuring-logging-for-a-library">
|
||||
<span id="library-config"></span><h3>为库配置日志<a class="headerlink" href="#configuring-logging-for-a-library" title="永久链接至标题">¶</a></h3>
|
||||
<p>在开发带日志的库时,你应该在文档中详细说明,你的库会如何使用日志——例如,使用的记录器的名称。还需要考虑其日志配置。如果使用库的应用程序不使用日志,且库代码调用日志进行记录,那么(如上一节所述)严重性为 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> 和更高级别的事件将被打印到 <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code>。这被认为是最好的默认行为。</p>
|
||||
<p>如果由于某种原因,你 <em>不</em> 希望在没有任何日志记录配置的情况下打印这些消息,则可以将无操作处理器附加到库的顶级记录器。这样可以避免打印消息,因为将始终为库的事件找到处理器:它不会产生任何输出。如果库用户配置应用程序使用的日志记录,可能是配置将添加一些处理器,如果级别已适当配置,则在库代码中进行的日志记录调用将正常地将输出发送给这些处理器。</p>
|
||||
<p>日志包中包含一个不做任何事情的处理器: <a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> (自 Python 3.1 起)。可以将此处理器的实例添加到库使用的日志记录命名空间的顶级记录器中( <em>如果</em> 你希望在没有日志记录配置的情况下阻止库的记录事件输出到 <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code> )。如果库 <em>foo</em> 的所有日志记录都是使用名称匹配 'foo.x' , 'foo.x.y' 等的记录器完成的,那么代码:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">logging</span>
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">'foo'</span><span class="p">)</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">NullHandler</span><span class="p">())</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>应该有预计的效果。如果一个组织生成了许多库,则指定的记录器名称可以是 “orgname.foo” 而不仅仅是 “foo” 。</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p>强烈建议你 <em>不要将</em> <a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> <em>以外的任何处理器添加到库的记录器中</em> 。这是因为处理器的配置是使用你的库的应用程序开发人员的权利。应用程序开发人员了解他们的目标受众以及哪些处理器最适合他们的应用程序:如果你在“底层”添加处理器,则可能会干扰他们执行单元测试和提供符合其要求的日志的能力。</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="logging-levels">
|
||||
<h2>日志级别<a class="headerlink" href="#logging-levels" title="永久链接至标题">¶</a></h2>
|
||||
<p>日志记录级别的数值在下表中给出。如果你想要定义自己的级别,并且需要它们具有相对于预定义级别的特定值,那么这你可能对以下内容感兴趣。如果你定义具有相同数值的级别,它将覆盖预定义的值;预定义的名称将失效。</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 48%" />
|
||||
<col style="width: 52%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>级别</p></th>
|
||||
<th class="head"><p>数值</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code></p></td>
|
||||
<td><p>50</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">ERROR</span></code></p></td>
|
||||
<td><p>40</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">WARNING</span></code></p></td>
|
||||
<td><p>30</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">INFO</span></code></p></td>
|
||||
<td><p>20</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">DEBUG</span></code></p></td>
|
||||
<td><p>10</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">NOTSET</span></code></p></td>
|
||||
<td><p>0</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>级别也可以与记录器关联,可以由开发人员设置,也可以通过加载保存的日志配置来设置。在记录器上调用记录方法时,记录器会将自己的级别与调用的方法的级别进行比较。如果记录器的级别高于调用的方法的级别,则实际上不会生成任何记录消息。这是控制日志记录输出详细程度的基本机制。</p>
|
||||
<p>日志消息被编码为 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 类的实例。当记录器决定实际记录一个事件时,将从记录消息创建一个 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 实例。</p>
|
||||
<p>使用 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 类的子例的实例 <em class="dfn">handlers</em>,可以为日志消息建立分派机制。处理器负责确保记录的消息(以 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 的形式)最终到达对该消息的目标受众(如最终用户、技术支持员工、系统管理员或开发人员)有用的一个或多个位置上。想要去到特定目标的 <a class="reference internal" href="../library/logging.html#logging.LogRecord" title="logging.LogRecord"><code class="xref py py-class docutils literal notranslate"><span class="pre">LogRecord</span></code></a> 实例会被传给相应的处理器。每个记录器可以有零、一或多个与之相关联的处理器(通过 <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a> 的 <a class="reference internal" href="../library/logging.html#logging.Logger.addHandler" title="logging.Logger.addHandler"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addHandler()</span></code></a> 方法)。除了与记录器直接关联的所有处理器之外,还会将消息分派给 <em>记录器的所有祖先关联的各个处理器*(除非某个记录器的 *propagate</em> 旗标被设为假值,这将使向祖先的传递在其处终止)。</p>
|
||||
<p>就像记录器一样,处理器可以具有与它们相关联的级别。处理器的级别作为过滤器,其方式与记录器级别相同。如果处理器决定调度一个事件,则使用 <code class="xref py py-meth docutils literal notranslate"><span class="pre">emit()</span></code> 方法将消息发送到其目标。大多数用户定义的 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 子类都需要重写 <code class="xref py py-meth docutils literal notranslate"><span class="pre">emit()</span></code>。</p>
|
||||
<section id="custom-levels">
|
||||
<span id="id1"></span><h3>自定义级别<a class="headerlink" href="#custom-levels" title="永久链接至标题">¶</a></h3>
|
||||
<p>定义你自己的级别是可能的,但不一定是必要的,因为现有级别是根据实践经验选择的。但是,如果你确信需要自定义级别,那么在执行此操作时应特别小心,如果你正在开发库,则 <em>定义自定义级别可能是一个非常糟糕的主意</em> 。 这是因为如果多个库作者都定义了他们自己的自定义级别,那么使用开发人员很难控制和解释这些多个库的日志记录输出,因为给定的数值对于不同的库可能意味着不同的东西。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="useful-handlers">
|
||||
<span id="id2"></span><h2>有用的处理器<a class="headerlink" href="#useful-handlers" title="永久链接至标题">¶</a></h2>
|
||||
<p>作为 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 基类的补充,提供了很多有用的子类:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a> 实例发送消息到流(类似文件对象)。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">FileHandler</span></code></a> 实例将消息发送到硬盘文件。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.BaseRotatingHandler" title="logging.handlers.BaseRotatingHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">BaseRotatingHandler</span></code></a> 是轮换日志文件的处理器的基类。它并不应该直接实例化。而应该使用 <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.RotatingFileHandler" title="logging.handlers.RotatingFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">RotatingFileHandler</span></code></a> 或 <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler" title="logging.handlers.TimedRotatingFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">TimedRotatingFileHandler</span></code></a> 代替它。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.RotatingFileHandler" title="logging.handlers.RotatingFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">RotatingFileHandler</span></code></a> 实例将消息发送到硬盘文件,支持最大日志文件大小和日志文件轮换。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler" title="logging.handlers.TimedRotatingFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">TimedRotatingFileHandler</span></code></a> 实例将消息发送到硬盘文件,以特定的时间间隔轮换日志文件。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SocketHandler" title="logging.handlers.SocketHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">SocketHandler</span></code></a> 实例将消息发送到 TCP/IP 套接字。从 3.4 开始,也支持 Unix 域套接字。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.DatagramHandler" title="logging.handlers.DatagramHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">DatagramHandler</span></code></a> 实例将消息发送到 UDP 套接字。从 3.4 开始,也支持 Unix 域套接字。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SMTPHandler" title="logging.handlers.SMTPHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">SMTPHandler</span></code></a> 实例将消息发送到指定的电子邮件地址。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SysLogHandler" title="logging.handlers.SysLogHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">SysLogHandler</span></code></a> 实例将消息发送到 Unix syslog 守护程序,可能在远程计算机上。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.NTEventLogHandler" title="logging.handlers.NTEventLogHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NTEventLogHandler</span></code></a> 实例将消息发送到 Windows NT/2000/XP 事件日志。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.MemoryHandler" title="logging.handlers.MemoryHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">MemoryHandler</span></code></a> 实例将消息发送到内存中的缓冲区,只要满足特定条件,缓冲区就会刷新。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.HTTPHandler" title="logging.handlers.HTTPHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">HTTPHandler</span></code></a> 实例使用 <code class="docutils literal notranslate"><span class="pre">GET</span></code> 或 <code class="docutils literal notranslate"><span class="pre">POST</span></code> 方法将消息发送到 HTTP 服务器。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.WatchedFileHandler" title="logging.handlers.WatchedFileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">WatchedFileHandler</span></code></a> 实例会监视他们要写入日志的文件。如果文件发生更改,则会关闭该文件并使用文件名重新打开。此处理器仅在类 Unix 系统上有用; Windows 不支持依赖的基础机制。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueHandler" title="logging.handlers.QueueHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">QueueHandler</span></code></a> 实例将消息发送到队列,例如在 <a class="reference internal" href="../library/queue.html#module-queue" title="queue: A synchronized queue class."><code class="xref py py-mod docutils literal notranslate"><span class="pre">queue</span></code></a> 或 <a class="reference internal" href="../library/multiprocessing.html#module-multiprocessing" title="multiprocessing: Process-based parallelism."><code class="xref py py-mod docutils literal notranslate"><span class="pre">multiprocessing</span></code></a> 模块中实现的队列。</p></li>
|
||||
<li><p><a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> 实例对错误消息不执行任何操作。它们由想要使用日志记录的库开发人员使用,但是想要避免如果库用户没有配置日志记录,则显示 'No handlers could be found for logger XXX' 消息的情况。更多有关信息,请参阅 <a class="reference internal" href="#library-config"><span class="std std-ref">为库配置日志</span></a> 。</p></li>
|
||||
</ol>
|
||||
<div class="versionadded">
|
||||
<p><span class="versionmodified added">3.1 新版功能: </span><a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> 类。</p>
|
||||
</div>
|
||||
<div class="versionadded">
|
||||
<p><span class="versionmodified added">3.2 新版功能: </span><a class="reference internal" href="../library/logging.handlers.html#logging.handlers.QueueHandler" title="logging.handlers.QueueHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">QueueHandler</span></code></a> 类。</p>
|
||||
</div>
|
||||
<p>The <a class="reference internal" href="../library/logging.handlers.html#logging.NullHandler" title="logging.NullHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">NullHandler</span></code></a> 、 <a class="reference internal" href="../library/logging.handlers.html#logging.StreamHandler" title="logging.StreamHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a> 和 <a class="reference internal" href="../library/logging.handlers.html#logging.FileHandler" title="logging.FileHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">FileHandler</span></code></a> 类在核心日志包中定义。其他处理器定义在 <a class="reference internal" href="../library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.handlers</span></code></a> 中。(还有另一个子模块 <a class="reference internal" href="../library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.config</span></code></a> ,用于配置功能)</p>
|
||||
<p>记录的消息通过 <a class="reference internal" href="../library/logging.html#logging.Formatter" title="logging.Formatter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Formatter</span></code></a> 类的实例进行格式化后呈现。 它们使用能与 % 运算符一起使用的格式字符串和字典进行初始化。</p>
|
||||
<p>要批量格式化多个消息,可以使用 <code class="xref py py-class docutils literal notranslate"><span class="pre">BufferingFormatter</span></code> 的实例。除了格式字符串(应用于批处理中的每个消息)之外,还提供了标题和尾部格式字符串。</p>
|
||||
<p>当基于记录器级别和处理器级别的过滤不够时,可以将 <a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Filter</span></code></a> 的实例添加到 <a class="reference internal" href="../library/logging.html#logging.Logger" title="logging.Logger"><code class="xref py py-class docutils literal notranslate"><span class="pre">Logger</span></code></a> 和 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 实例(通过它们的 <a class="reference internal" href="../library/logging.html#logging.Handler.addFilter" title="logging.Handler.addFilter"><code class="xref py py-meth docutils literal notranslate"><span class="pre">addFilter()</span></code></a> 方法)。在决定进一步处理消息之前,记录器和处理器都会查询其所有过滤器以获得许可。如果任何过滤器返回 false 值,则不会进一步处理该消息。</p>
|
||||
<p>基本 <a class="reference internal" href="../library/logging.html#logging.Filter" title="logging.Filter"><code class="xref py py-class docutils literal notranslate"><span class="pre">Filter</span></code></a> 的功能允许按特定的记录器名称进行过滤。如果使用此功能,则允许通过过滤器发送到指定记录器及其子项的消息,并丢弃其他所有消息。</p>
|
||||
</section>
|
||||
<section id="exceptions-raised-during-logging">
|
||||
<span id="logging-exceptions"></span><h2>记录日志时引发的异常<a class="headerlink" href="#exceptions-raised-during-logging" title="永久链接至标题">¶</a></h2>
|
||||
<p>logging 包被设计为,当在生产环境下使用时,忽略记录日志时发生的异常。这样,处理与日志相关的事件时发生的错误(例如日志配置错误、网络或其它类似错误)不会导致使用日志的应用程序终止。</p>
|
||||
<p><a class="reference internal" href="../library/exceptions.html#SystemExit" title="SystemExit"><code class="xref py py-class docutils literal notranslate"><span class="pre">SystemExit</span></code></a> 和 <a class="reference internal" href="../library/exceptions.html#KeyboardInterrupt" title="KeyboardInterrupt"><code class="xref py py-class docutils literal notranslate"><span class="pre">KeyboardInterrupt</span></code></a> 异常永远不会被忽略。在 <a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 的子类的 <code class="xref py py-meth docutils literal notranslate"><span class="pre">emit()</span></code> 方法中发生的其它异常将被传递给其 <code class="xref py py-meth docutils literal notranslate"><span class="pre">handleError()</span></code> 方法。</p>
|
||||
<p><a class="reference internal" href="../library/logging.html#logging.Handler" title="logging.Handler"><code class="xref py py-class docutils literal notranslate"><span class="pre">Handler</span></code></a> 中的 <code class="xref py py-meth docutils literal notranslate"><span class="pre">handleError()</span></code> 的默认实现是检查是否设置了模块级变量 <code class="xref py py-data docutils literal notranslate"><span class="pre">raiseExceptions</span></code>。如有设置,则会将回溯打印到 <a class="reference internal" href="../library/sys.html#sys.stderr" title="sys.stderr"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.stderr</span></code></a>。如果未设置,则忽略异常。</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p><code class="xref py py-data docutils literal notranslate"><span class="pre">raiseExceptions</span></code> 的默认值是 <code class="docutils literal notranslate"><span class="pre">True</span></code>。这是因为在开发期间,你通常想要在发生异常时收到通知。建议你将 <code class="xref py py-data docutils literal notranslate"><span class="pre">raiseExceptions</span></code> 设为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 供生产环境下使用。</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="using-arbitrary-objects-as-messages">
|
||||
<span id="arbitrary-object-messages"></span><h2>使用任意对象作为消息<a class="headerlink" href="#using-arbitrary-objects-as-messages" title="永久链接至标题">¶</a></h2>
|
||||
<p>在前面的部分和示例中,都假设记录事件时传递的消息是字符串。 但是,这不是唯一的可能性。你可以将任意对象作为消息传递,并且当日志记录系统需要将其转换为字符串表示时,将调用其 <code class="xref py py-meth docutils literal notranslate"><span class="pre">__</span> <span class="pre">str__()</span></code> 方法。实际上,如果你愿意,你可以完全避免计算字符串表示。例如, <a class="reference internal" href="../library/logging.handlers.html#logging.handlers.SocketHandler" title="logging.handlers.SocketHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">SocketHandler</span></code></a> 用 pickle 处理事件后,通过网络发送。</p>
|
||||
</section>
|
||||
<section id="optimization">
|
||||
<h2>优化<a class="headerlink" href="#optimization" title="永久链接至标题">¶</a></h2>
|
||||
<p>消息参数的格式化将被推迟,直到无法避免。但是,计算传递给日志记录方法的参数也可能很消耗资源,如果记录器只是丢弃你的事件,你可能希望避免这样做。要决定做什么,可以调用 <a class="reference internal" href="../library/logging.html#logging.Logger.isEnabledFor" title="logging.Logger.isEnabledFor"><code class="xref py py-meth docutils literal notranslate"><span class="pre">isEnabledFor()</span></code></a> 方法,该方法接受一个 level 参数,如果记录器为该级别的调用创建了该事件,则返回 true 。 你可以写这样的代码:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">logger</span><span class="o">.</span><span class="n">isEnabledFor</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">):</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">'Message with </span><span class="si">%s</span><span class="s1">, </span><span class="si">%s</span><span class="s1">'</span><span class="p">,</span> <span class="n">expensive_func1</span><span class="p">(),</span>
|
||||
<span class="n">expensive_func2</span><span class="p">())</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>因此,如果记录器的阈值设置在“DEBUG”以上,则永远不会调用 <code class="xref py py-func docutils literal notranslate"><span class="pre">expensive_func1()</span></code> 和 <code class="xref py py-func docutils literal notranslate"><span class="pre">expensive_func2()</span></code> 。</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p>在某些情况下, <a class="reference internal" href="../library/logging.html#logging.Logger.isEnabledFor" title="logging.Logger.isEnabledFor"><code class="xref py py-meth docutils literal notranslate"><span class="pre">isEnabledFor()</span></code></a> 本身可能比你想要的更消耗资源(例如,对于深度嵌套的记录器,其中仅在记录器层次结构中设置了显式级别)。在这种情况下(或者如果你想避免在紧密循环中调用方法),你可以在本地或实例变量中将调用的结果缓存到 <a class="reference internal" href="../library/logging.html#logging.Logger.isEnabledFor" title="logging.Logger.isEnabledFor"><code class="xref py py-meth docutils literal notranslate"><span class="pre">isEnabledFor()</span></code></a> ,并使用它而不是每次调用方法。在日志记录配置在应用程序运行时动态更改(这不常见)时,只需要重新计算这样的缓存值即可。</p>
|
||||
</div>
|
||||
<p>对于需要对收集的日志信息进行更精确控制的特定应用程序,还可以进行其他优化。以下列出了在日志记录过程中您可以避免的非必须处理操作:</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 54%" />
|
||||
<col style="width: 46%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>你不想收集的内容</p></th>
|
||||
<th class="head"><p>如何避免收集它</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p>有关调用来源的信息</p></td>
|
||||
<td><p>将 <code class="docutils literal notranslate"><span class="pre">logging._srcfile</span></code> 设置为 <code class="docutils literal notranslate"><span class="pre">None</span></code> 。这避免了调用 <a class="reference internal" href="../library/sys.html#sys._getframe" title="sys._getframe"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys._getframe()</span></code></a> ,如果 PyPy 支持 Python 3.x ,这可能有助于加速 PyPy (无法加速使用 <a class="reference internal" href="../library/sys.html#sys._getframe" title="sys._getframe"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys._getframe()</span></code></a> 的代码)等环境中的代码.</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p>线程信息</p></td>
|
||||
<td><p>将 <code class="docutils literal notranslate"><span class="pre">logging.logThreads</span></code> 置为 <code class="docutils literal notranslate"><span class="pre">0</span></code> 。</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p>进程信息</p></td>
|
||||
<td><p>将 <code class="docutils literal notranslate"><span class="pre">logging.logProcesses</span></code> 置为 <code class="docutils literal notranslate"><span class="pre">0</span></code> 。</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>另请注意,核心日志记录模块仅包含基本处理器。如果你不导入 <a class="reference internal" href="../library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.handlers</span></code></a> 和 <a class="reference internal" href="../library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.config</span></code></a> ,它们将不会占用任何内存。</p>
|
||||
<div class="admonition seealso">
|
||||
<p class="admonition-title">参见</p>
|
||||
<dl class="simple">
|
||||
<dt>模块 <a class="reference internal" href="../library/logging.html#module-logging" title="logging: Flexible event logging system for applications."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging</span></code></a></dt><dd><p>日志记录模块的 API 参考。</p>
|
||||
</dd>
|
||||
<dt><a class="reference internal" href="../library/logging.config.html#module-logging.config" title="logging.config: Configuration of the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.config</span></code></a> 模块</dt><dd><p>日志记录模块的配置 API 。</p>
|
||||
</dd>
|
||||
<dt><a class="reference internal" href="../library/logging.handlers.html#module-logging.handlers" title="logging.handlers: Handlers for the logging module."><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging.handlers</span></code></a> 模块</dt><dd><p>日志记录模块附带的有用处理器。</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><a class="reference internal" href="logging-cookbook.html#logging-cookbook"><span class="std std-ref">日志操作手册</span></a></p>
|
||||
</div>
|
||||
</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="#">日志指南</a><ul>
|
||||
<li><a class="reference internal" href="#basic-logging-tutorial">日志基础教程</a><ul>
|
||||
<li><a class="reference internal" href="#when-to-use-logging">什么时候使用日志</a></li>
|
||||
<li><a class="reference internal" href="#a-simple-example">一个简单的例子</a></li>
|
||||
<li><a class="reference internal" href="#logging-to-a-file">记录日志到文件</a></li>
|
||||
<li><a class="reference internal" href="#logging-from-multiple-modules">从多个模块记录日志</a></li>
|
||||
<li><a class="reference internal" href="#logging-variable-data">记录变量数据</a></li>
|
||||
<li><a class="reference internal" href="#changing-the-format-of-displayed-messages">更改显示消息的格式</a></li>
|
||||
<li><a class="reference internal" href="#displaying-the-date-time-in-messages">在消息中显示日期/时间</a></li>
|
||||
<li><a class="reference internal" href="#next-steps">后续步骤</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#advanced-logging-tutorial">进阶日志教程</a><ul>
|
||||
<li><a class="reference internal" href="#logging-flow">记录流程</a></li>
|
||||
<li><a class="reference internal" href="#loggers">记录器</a></li>
|
||||
<li><a class="reference internal" href="#handlers">处理器</a></li>
|
||||
<li><a class="reference internal" href="#formatters">格式器</a></li>
|
||||
<li><a class="reference internal" href="#configuring-logging">配置日志记录</a></li>
|
||||
<li><a class="reference internal" href="#what-happens-if-no-configuration-is-provided">如果没有提供配置会发生什么</a></li>
|
||||
<li><a class="reference internal" href="#configuring-logging-for-a-library">为库配置日志</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#logging-levels">日志级别</a><ul>
|
||||
<li><a class="reference internal" href="#custom-levels">自定义级别</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#useful-handlers">有用的处理器</a></li>
|
||||
<li><a class="reference internal" href="#exceptions-raised-during-logging">记录日志时引发的异常</a></li>
|
||||
<li><a class="reference internal" href="#using-arbitrary-objects-as-messages">使用任意对象作为消息</a></li>
|
||||
<li><a class="reference internal" href="#optimization">优化</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="functional.html"
|
||||
title="上一章">函数式编程指引</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="logging-cookbook.html"
|
||||
title="下一章">日志专题手册</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/howto/logging.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="logging-cookbook.html" title="日志专题手册"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="functional.html" title="函数式编程指引"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
476
web/python-docs/howto/pyporting.html
Normal file
476
web/python-docs/howto/pyporting.html
Normal file
@@ -0,0 +1,476 @@
|
||||
|
||||
<!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>将 Python 2 代码迁移到 Python 3 — 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="将扩展模块移植到 Python 3" href="cporting.html" />
|
||||
<link rel="prev" title="Python 指南" href="index.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/pyporting.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="#">将 Python 2 代码迁移到 Python 3</a><ul>
|
||||
<li><a class="reference internal" href="#the-short-explanation">简要说明</a></li>
|
||||
<li><a class="reference internal" href="#details">详情</a><ul>
|
||||
<li><a class="reference internal" href="#drop-support-for-python-2-6-and-older">删除对Python 2.6及更早版本的支持</a></li>
|
||||
<li><a class="reference internal" href="#make-sure-you-specify-the-proper-version-support-in-your-setup-py-file">确保你在你的``setup.py``文件中指定适当的版本支持</a></li>
|
||||
<li><a class="reference internal" href="#have-good-test-coverage">良好的测试覆盖率</a></li>
|
||||
<li><a class="reference internal" href="#learn-the-differences-between-python-2-3">了解Python 2 和 3之间的区别</a></li>
|
||||
<li><a class="reference internal" href="#update-your-code">更新代码</a><ul>
|
||||
<li><a class="reference internal" href="#division">除法</a></li>
|
||||
<li><a class="reference internal" href="#text-versus-binary-data">文本与二进制数据</a></li>
|
||||
<li><a class="reference internal" href="#use-feature-detection-instead-of-version-detection">使用特征检测而不是版本检测</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#prevent-compatibility-regressions">防止兼容性退步</a></li>
|
||||
<li><a class="reference internal" href="#check-which-dependencies-block-your-transition">检查哪些依赖性会阻碍你的过渡</a></li>
|
||||
<li><a class="reference internal" href="#update-your-setup-py-file-to-denote-python-3-compatibility">更新你的``setup.py``文件以表示对Python 3的兼容</a></li>
|
||||
<li><a class="reference internal" href="#use-continuous-integration-to-stay-compatible">使用持续集成以保持兼容</a></li>
|
||||
<li><a class="reference internal" href="#consider-using-optional-static-type-checking">考虑使用可选的静态类型检查</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="index.html"
|
||||
title="上一章">Python 指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="cporting.html"
|
||||
title="下一章">将扩展模块移植到 Python 3</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/howto/pyporting.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/howto/pyporting.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="cporting.html" title="将扩展模块移植到 Python 3"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="index.html" title="Python 指南"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="porting-python-2-code-to-python-3">
|
||||
<span id="pyporting-howto"></span><h1>将 Python 2 代码迁移到 Python 3<a class="headerlink" href="#porting-python-2-code-to-python-3" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>Brett Cannon</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="topic">
|
||||
<p class="topic-title">摘要</p>
|
||||
<p>Python 3 是 Python 的未来,但 Python 2 仍处于活跃使用阶段,最好让您的项目在两个主要版本的Python 上都可用。本指南旨在帮助您了解如何最好地同时支持 Python 2 和 3。</p>
|
||||
<p>如果您希望迁移扩展模块而不是纯 Python 代码,请参阅 <a class="reference internal" href="cporting.html#cporting-howto"><span class="std std-ref">将扩展模块移植到 Python 3</span></a>。</p>
|
||||
<p>如果你想了解核心 Python 开发者对于 Python 3 的出现有何看法,你可以阅读 Nick Coghlan 的 <a class="reference external" href="https://ncoghlan-devs-python-notes.readthedocs.io/en/latest/python3/questions_and_answers.html">Python 3 Q & A</a> 或 Brett Cannon 的 <a class="reference external" href="https://snarky.ca/why-python-3-exists">为什么要有 Python 3</a>.</p>
|
||||
<p>有关迁移的帮助,您可以通过电子邮件向 <a class="reference external" href="https://mail.python.org/mailman/listinfo/python-porting">python-porting</a> 邮件列表发送问题。</p>
|
||||
</div>
|
||||
<section id="the-short-explanation">
|
||||
<h2>简要说明<a class="headerlink" href="#the-short-explanation" title="永久链接至标题">¶</a></h2>
|
||||
<p>为了使你的项目与单源Python 2/3兼容,基本步骤如下:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>只担心支持Python 2.7的问题</p></li>
|
||||
<li><p>确保有良好的测试覆盖率(可以用 <a class="reference external" href="https://pypi.org/project/coverage">coverage.py</a> 来完成此任务;用 <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">coverage</span></code> 安装)</p></li>
|
||||
<li><p>了解Python 2 和 3之间的区别</p></li>
|
||||
<li><p>使用 <a class="reference external" href="http://python-future.org/automatic_conversion.html">Futurize</a> (<a class="reference external" href="https://python-modernize.readthedocs.io/">或Modernize</a>) 来更新你的代码 (例如``python -m pip install future``)。</p></li>
|
||||
<li><p>Use <a class="reference external" href="https://pypi.org/project/pylint">Pylint</a> to help make sure you don't regress on your Python 3 support
|
||||
(<code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">pylint</span></code>)</p></li>
|
||||
<li><p>使用 <a class="reference external" href="https://pypi.org/project/caniusepython3">caniusepython3</a> 来找出你的哪些依赖关系阻碍了你对 Python 3 的使用 (<code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">caniusepython3</span></code>)</p></li>
|
||||
<li><p>一旦你的依赖关系不再阻碍你,使用持续集成来确保你与 Python 2 和 3 保持兼容 (<a class="reference external" href="https://pypi.org/project/tox">tox</a> 可以帮助对多个版本的 Python 进行测试; <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">tox</span></code>)</p></li>
|
||||
<li><p>考虑使用可选的静态类型检查来确保你的类型用法在 Python 2 和 3 中都适用 (例如使用 <a class="reference external" href="http://mypy-lang.org/">mypy</a> 来检查你在 Python 2 和 Python 3 中的类型)。</p></li>
|
||||
</ol>
|
||||
</section>
|
||||
<section id="details">
|
||||
<h2>详情<a class="headerlink" href="#details" title="永久链接至标题">¶</a></h2>
|
||||
<p>同时支持Python 2和3的一个关键点是,你可以从**今天**开始!即使你的依赖关系还不支持Python 3,也不意味着你不能现在就对你的代码进行现代化改造以支持Python 3。支持Python 3所需的大多数变化都会使代码更干净,甚至在Python 2的代码中也会使用更新的做法。</p>
|
||||
<p>另一个关键点是,使你的Python 2代码现代化以支持Python 3在很大程度上是为你自动化的。虽然由于Python 3清晰区分了文本数据与二进制数据,你可能必须做出一些API决定。但现在已经为你完成了大部分低级别的工作,因此至少可以立即从自动化变化中受益。</p>
|
||||
<p>当你继续阅读关于迁移你的代码以同时支持Python 2和3的细节时,请牢记这些关键点。</p>
|
||||
<section id="drop-support-for-python-2-6-and-older">
|
||||
<h3>删除对Python 2.6及更早版本的支持<a class="headerlink" href="#drop-support-for-python-2-6-and-older" title="永久链接至标题">¶</a></h3>
|
||||
<p>虽然你可以让 Python 2.5 与 Python 3 一起工作,但如果你只需要与 Python 2.7 一起工作,那就会 <strong>更加容易</strong>。 如果放弃 Python 2.5 不是一种选择,那么 <a class="reference external" href="https://pypi.org/project/six">six</a> 项目可以帮助你同时支持 Python 2.5 和 3 (<code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">six</span></code>)。 不过请注意,本 HOWTO 中列出的几乎所有项目都有可能会不再可用。</p>
|
||||
<p>如果你能够跳过Python 2.5和更早的版本,那么对你的代码所做的必要修改应该看起来和感觉上都是你已经习惯的Python代码。在最坏的情况下,你将不得不使用一个函数而不是一个实例方法,或者不得不导入一个函数而不是使用一个内置的函数,但除此之外,整体的转变应该不会让你感到陌生。</p>
|
||||
<p>但你的目标应该是只支持 Python 2.7。Python 2.6 不再被免费支持,因此也就没有得到错误修复。这意味着**你**必须解决你在Python 2.6上遇到的任何问题。本HOWTO中提到的一些工具也不支持Python 2.6 (例如,<a class="reference external" href="https://pypi.org/project/pylint">Pylint</a>),随着时间的推移,这将变得越来越普遍。如果你只支持你必须支持的Python版本,那么对你来说会更容易。</p>
|
||||
</section>
|
||||
<section id="make-sure-you-specify-the-proper-version-support-in-your-setup-py-file">
|
||||
<h3>确保你在你的``setup.py``文件中指定适当的版本支持<a class="headerlink" href="#make-sure-you-specify-the-proper-version-support-in-your-setup-py-file" title="永久链接至标题">¶</a></h3>
|
||||
<p>在你的``setup.py``文件中,你应该有适当的 <a class="reference external" href="https://pypi.org/classifiers">trove classifier</a> 指定你支持哪些版本的 Python。由于你的项目还不支持 Python 3,你至少应该指定``Programming Language :: Python :: 2 :: Only``。理想情况下,你还应该指定你所支持的Python的每个主要/次要版本,例如:<code class="docutils literal notranslate"><span class="pre">Programming</span> <span class="pre">Language</span> <span class="pre">::</span> <span class="pre">Python</span> <span class="pre">::</span> <span class="pre">2.7</span></code>。.</p>
|
||||
</section>
|
||||
<section id="have-good-test-coverage">
|
||||
<h3>良好的测试覆盖率<a class="headerlink" href="#have-good-test-coverage" title="永久链接至标题">¶</a></h3>
|
||||
<p>一旦你的代码支持了你希望的Python 2的最老版本,你将希望确保你的测试套件有良好的覆盖率。一个好的经验法则是,如果你想对你的测试套件有足够的信心,在让工具重写你的代码后出现的任何故障都是工具中的实际错误,而不是你的代码中的错误。如果你想要一个目标数字,试着获得超过80%的覆盖率(如果你发现很难获得好于90%的覆盖率,也不要感到遗憾)。如果你还没有一个测量测试覆盖率的工具,<a class="reference external" href="https://pypi.org/project/coverage">那么推荐使用coverage.py</a>。</p>
|
||||
</section>
|
||||
<section id="learn-the-differences-between-python-2-3">
|
||||
<h3>了解Python 2 和 3之间的区别<a class="headerlink" href="#learn-the-differences-between-python-2-3" title="永久链接至标题">¶</a></h3>
|
||||
<p>一旦你的代码经过了很好的测试,你就可以开始把你的代码移植到 Python 3 上了! 但是为了充分了解你的代码将发生怎样的变化,以及你在编码时要注意什么,你将会想要了解 Python 3 相比 Python 2 的变化。 通常来说,两个最好的方法是阅读 Python 3 每个版本的 <a class="reference internal" href="../whatsnew/index.html#whatsnew-index"><span class="std std-ref">"What's New"</span></a> 文档和 <a class="reference external" href="http://python3porting.com/">Porting to Python 3</a> 书(在线免费版本)。还有一个来自 Python-Future 项目的便利 <a class="reference external" href="http://python-future.org/compatible_idioms.html">cheat sheet</a>。</p>
|
||||
</section>
|
||||
<section id="update-your-code">
|
||||
<h3>更新代码<a class="headerlink" href="#update-your-code" title="永久链接至标题">¶</a></h3>
|
||||
<p>一旦你觉得你知道了 Python 3 与 Python 2 相比有什么不同,就是时候更新你的代码了! 你可以选择两种工具来自动移植你的代码: <a class="reference external" href="http://python-future.org/automatic_conversion.html">Futurize</a> 和 <a class="reference external" href="https://python-modernize.readthedocs.io/">Modernize</a>。 你选择哪个工具将取决于你希望你的代码有多像 Python 3。 <a class="reference external" href="http://python-future.org/automatic_conversion.html">Futurize</a> 尽力使 Python 3 的习性和做法在 Python 2 中存在,例如,从 Python 3 中回传 <code class="docutils literal notranslate"><span class="pre">bytes</span></code> 类型,这样你就可以在 Python 的主要版本之间实现语义上的平等。 另一方面,<a class="reference external" href="https://python-modernize.readthedocs.io/">Modernize</a> 更加保守,它针对的是 Python 2/3 的子集,直接依靠 <a class="reference external" href="https://pypi.org/project/six">six</a> 来帮助提供兼容性。 由于 Python 3 是未来,最好考虑 Futurize,以开始适应 Python 3 所引入的、你还不习惯的任何新做法。</p>
|
||||
<p>无论你选择哪种工具,它们都会更新你的代码,使之在Python 3下运行,同时与你开始使用的Python 2版本保持兼容。根据你想要的保守程度,你可能想先在你的测试套件上运行该工具,并目测差异以确保转换的准确性。在你转换了你的测试套件并验证了所有的测试仍然如期通过后,你就可以转换你的应用程序代码了,因为你知道任何测试失败都是转译的错误。</p>
|
||||
<p>不幸的是,这些工具不能自动地使你的代码在Python 3下工作,因此有一些东西你需要手动更新以获得对Python 3的完全支持(这些步骤在不同的工具中是必要的)。阅读你选择使用的工具的文档,看看它默认修复了什么,以及它可以选择做什么,以了解哪些将(不)为你修复,哪些你可能必须自己修复(例如,在Modernize中使用``io.open()``覆写内置的``open()``函数默认是关闭的)。不过幸运的是,只有几件需要注意的事情,可以说是大问题,如果不注意的话,可能很难调试。</p>
|
||||
<section id="division">
|
||||
<h4>除法<a class="headerlink" href="#division" title="永久链接至标题">¶</a></h4>
|
||||
<p>在Python 3中,<code class="docutils literal notranslate"><span class="pre">5</span> <span class="pre">/</span> <span class="pre">2</span> <span class="pre">==</span> <span class="pre">2.5``而不是``2</span></code>;所有``int``数值之间的除法都会产生一个``float``、这个变化实际上从2002年发布的Python 2.2开始就已经计划好了。从那时起,我们就鼓励用户在所有使用``/<code class="docutils literal notranslate"><span class="pre">和</span></code>//<code class="docutils literal notranslate"><span class="pre">运算符的文件中添加``from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">division</span></code>,或者在运行解释器时使用``-Q``标志。如果你没有这样做,那么你需要检查你的代码并做两件事。</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>添加 <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">division</span></code> 到你的文件。</p></li>
|
||||
<li><p>根据需要更新任何除法运算符,要么使用 <code class="docutils literal notranslate"><span class="pre">//</span></code> 来使用向下取整除法,要么继续使用 <code class="docutils literal notranslate"><span class="pre">/</span></code> 并得到一个浮点数</p></li>
|
||||
</ol>
|
||||
<p>之所以没有简单地将 <code class="docutils literal notranslate"><span class="pre">/</span></code> 自动翻译成 <code class="docutils literal notranslate"><span class="pre">//</span></code>,是因为如果一个对象定义了一个 <code class="docutils literal notranslate"><span class="pre">__truediv__</span></code> 方法,但没有定义 <code class="docutils literal notranslate"><span class="pre">__floordiv__</span></code>,那么你的代码就会运行失败(例如,一个用户定义的类用 <code class="docutils literal notranslate"><span class="pre">/</span></code> 来表示一些操作,但没有用 <code class="docutils literal notranslate"><span class="pre">//</span></code> 来表示同样的事情或根本没有定义)。</p>
|
||||
</section>
|
||||
<section id="text-versus-binary-data">
|
||||
<h4>文本与二进制数据<a class="headerlink" href="#text-versus-binary-data" title="永久链接至标题">¶</a></h4>
|
||||
<p>在Python 2中,你可以对文本和二进制数据都使用``str``类型。不幸的是,这两个不同概念的融合可能会导致脆弱的代码,有时对任何一种数据都有效,有时则无效。如果人们没有明确说明某种接受``str``东西可以接受文本或二进制数据,而不是一种特定的类型,这也会导致API的混乱。这使情况变得复杂,特别是对于任何支持多种语言的人来说,因为API在声称支持文本数据时不会显式支持``unicode``。</p>
|
||||
<p>为了使文本和二进制数据之间的区别更加清晰和明显,Python 3做了大多数在互联网时代创建的语言所做的事情,使文本和二进制数据成为不能盲目混合在一起的不同类型(Python早于互联网的广泛使用)。对于任何只处理文本或只处理二进制数据的代码,这种分离并不构成问题。但是对于必须处理这两种数据的代码来说,这确实意味着你现在可能必须关心你何时使用文本或二进制数据,这就是为什么这不能完全自动化迁移。</p>
|
||||
<p>首先,你需要决定哪些 API 接受文本,哪些接受二进制(由于保持代码工作的难度,<strong>强烈</strong> 建议你不要设计同时接受两种数据的 API;如前所述,这很难做得好)。在 Python 2 中,这意味着要确保处理文本的 API 能够与 <code class="docutils literal notranslate"><span class="pre">unicode</span></code> 一起工作,而处理二进制数据的 API 能够与 Python 3 中的 <code class="docutils literal notranslate"><span class="pre">bytes</span></code> 类型一起工作(在 Python 2 中是 <code class="docutils literal notranslate"><span class="pre">str</span></code> 的一个子集,在 Python 2 中作为 <code class="docutils literal notranslate"><span class="pre">bytes</span></code> 类型的别名)。通常最大的问题是意识到哪些方法同时存在于 Python 2 和 3 的哪些类型上 (对于文本来说,Python 2 中是 <code class="docutils literal notranslate"><span class="pre">unicode</span></code>,Python 3 中是 <code class="docutils literal notranslate"><span class="pre">str</span></code>,对于二进制来说,Python 2 中是 <code class="docutils literal notranslate"><span class="pre">str</span></code>/<code class="docutils literal notranslate"><span class="pre">bytes</span></code>,Python 3 中是``bytes``)。 下表列出了每个数据类型在 Python 2 和 3 中的 <strong>独特</strong> 的方法 (例如,<code class="docutils literal notranslate"><span class="pre">decode()</span></code> 方法在 Python 2 或 3 中的等价二进制数据类型上是可用的,但是它不能在 Python 2 和 3 之间被文本数据类型一致使用,因为 Python 3 中的 <code class="docutils literal notranslate"><span class="pre">str</span></code> 没有这个方法)。 请注意,从 Python 3.5 开始,<code class="docutils literal notranslate"><span class="pre">__mod__</span></code> 方法被添加到 bytes 类型中。</p>
|
||||
<table class="docutils align-default">
|
||||
<colgroup>
|
||||
<col style="width: 53%" />
|
||||
<col style="width: 47%" />
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr class="row-odd"><td><p><strong>文本数据</strong></p></td>
|
||||
<td><p><strong>二进制数据</strong></p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p></p></td>
|
||||
<td><p>decode</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p>encode</p></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p>format</p></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p>isdecimal</p></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p>isnumeric</p></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>通过在你的代码边缘对二进制数据和文本进行编码和解码,可以使这种区分更容易处理。这意味着,当你收到二进制数据的文本时,你应该立即对其进行解码。而如果你的代码需要将文本作为二进制数据发送,那么就尽可能晚地对其进行编码。这使得你的代码在内部只与文本打交道,从而不必再去跟踪你所处理的数据类型。</p>
|
||||
<p>下一个问题是确保你知道你的代码中的字符串字头是代表文本还是二进制数据。你应该给任何呈现二进制数据的字面符号添加一个``b``前缀。对于文本,你应该给文本字面添加一个``u``前缀。(有一个 <a class="reference internal" href="../library/__future__.html#module-__future__" title="__future__: Future statement definitions"><code class="xref py py-mod docutils literal notranslate"><span class="pre">__future__</span></code></a> 导入来强制所有未指定的字头为Unicode,但实际使用情况表明它并不像给所有字头显式添加一个``b``或``u``前缀那样有效)</p>
|
||||
<p>作为这种二分法的一部分,你还需要小心打开文件。除非你一直在 Windows 上工作,否则你有可能在打开二进制文件时没有一直费心地添加``b``模式 (例如,用``rb``进行二进制读取)。 在 Python 3 下,二进制文件和文本文件显然是不同的,而且是相互不兼容的;详见 <a class="reference internal" href="../library/io.html#module-io" title="io: Core tools for working with streams."><code class="xref py py-mod docutils literal notranslate"><span class="pre">io</span></code></a> 模块。因此,你必须**决定**一个文件是用于二进制访问(允许读取和/或写入二进制数据)还是文本访问(允许读取和/或写入文本数据)。你还应该使用 <a class="reference internal" href="../library/io.html#io.open" title="io.open"><code class="xref py py-func docutils literal notranslate"><span class="pre">io.open()</span></code></a> 来打开文件,而不是内置的 <a class="reference internal" href="../library/functions.html#open" title="open"><code class="xref py py-func docutils literal notranslate"><span class="pre">open()</span></code></a> 函数,因为 <a class="reference internal" href="../library/io.html#module-io" title="io: Core tools for working with streams."><code class="xref py py-mod docutils literal notranslate"><span class="pre">io</span></code></a> 模块从 Python 2 到 3 是一致的,而内置的 <a class="reference internal" href="../library/functions.html#open" title="open"><code class="xref py py-func docutils literal notranslate"><span class="pre">open()</span></code></a> 函数则不是 (在 Python 3 中它实际上是 <a class="reference internal" href="../library/io.html#io.open" title="io.open"><code class="xref py py-func docutils literal notranslate"><span class="pre">io.open()</span></code></a>)。不要理会使用 <a class="reference internal" href="../library/codecs.html#codecs.open" title="codecs.open"><code class="xref py py-func docutils literal notranslate"><span class="pre">codecs.open()</span></code></a> 的过时做法,因为这只是为了保持与 Python 2.5 的兼容性。</p>
|
||||
<p>在Python 2和3中,<code class="docutils literal notranslate"><span class="pre">str``和``bytes``的构造函数对相同的参数有不同的语义。在Python</span> <span class="pre">2中,传递一个整数给``bytes</span></code>,你将得到整数的字符串表示:<code class="docutils literal notranslate"><span class="pre">bytes(3)</span> <span class="pre">==</span> <span class="pre">'3'</span></code>。但是在Python 3中,一个整数参数传递给``bytes``将给你一个与指定的整数一样长的bytes对象,其中充满了空字节:<code class="docutils literal notranslate"><span class="pre">bytes(3)</span> <span class="pre">==</span> <span class="pre">b'\x00\x00\x00'</span></code>。当把bytes对象传给``str``时,类似的担心是必要的。 在Python 2中,你只是又得到了该bytes对象:<code class="docutils literal notranslate"><span class="pre">str(b'3')</span> <span class="pre">==</span> <span class="pre">b'3'</span></code>。但是在Python 3中,你得到bytes对象的字符串表示:<code class="docutils literal notranslate"><span class="pre">str(b'3')</span> <span class="pre">==</span> <span class="pre">"b'3'"</span></code>。</p>
|
||||
<p>最后,二进制数据的索引需要仔细处理(切片 <strong>不需要</strong> 任何特殊处理)。在 Python 2 中 <code class="docutils literal notranslate"><span class="pre">b'123'[1]</span> <span class="pre">==</span> <span class="pre">b'2'</span></code>,而在 Python 3 中``b'123'[1] == 50``。 因为二进制数据只是二进制数的集合,Python 3 会返回你索引的字节的整数值。 但是在 Python 2 中,因为 <code class="docutils literal notranslate"><span class="pre">bytes</span> <span class="pre">==</span> <span class="pre">str</span></code>,索引会返回一个单项的字节片断。 <a class="reference external" href="https://pypi.org/project/six">six</a> 项目有一个名为 <code class="docutils literal notranslate"><span class="pre">six.indexbytes()</span></code> 的函数,它将像在 Python 3 中一样返回一个整数: <code class="docutils literal notranslate"><span class="pre">six.indexbytes(b'123',</span> <span class="pre">1)</span></code>。</p>
|
||||
<p>总结一下:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>决定你的API中哪些采用文本,哪些采用二进制数据</p></li>
|
||||
<li><p>确保你对文本工作的代码也能对``unicode``工作,对二进制数据的代码在Python 2中能对``bytes``工作(关于每种类型不能使用的方法,见上表)。</p></li>
|
||||
<li><p>用``b``前缀标记所有二进制字词,用``u``前缀标记文本字词</p></li>
|
||||
<li><p>尽快将二进制数据解码为文本,尽可能晚地将文本编码为二进制数据</p></li>
|
||||
<li><p>使用 <a class="reference internal" href="../library/io.html#io.open" title="io.open"><code class="xref py py-func docutils literal notranslate"><span class="pre">io.open()</span></code></a> 打开文件,并确保在适当时候指定 <code class="docutils literal notranslate"><span class="pre">b</span></code> 模式。</p></li>
|
||||
<li><p>在对二进制数据进行索引时要小心</p></li>
|
||||
</ol>
|
||||
</section>
|
||||
<section id="use-feature-detection-instead-of-version-detection">
|
||||
<h4>使用特征检测而不是版本检测<a class="headerlink" href="#use-feature-detection-instead-of-version-detection" title="永久链接至标题">¶</a></h4>
|
||||
<p>你不可避免地会有一些代码需要根据运行的 Python 版本来选择要做什么。做到这一点的最好方法是对你运行的 Python 版本是否支持你所需要的东西进行特征检测。如果由于某种原因这不起作用,那么你应该让版本检测针对 Python 2 而不是 Python 3。为了帮助解释这个问题,让我们看一个例子。</p>
|
||||
<p>假设你需要访问 <a class="reference internal" href="../library/importlib.html#module-importlib" title="importlib: The implementation of the import machinery."><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib</span></code></a> 的一个功能,该功能自Python 3.3开始在Python的标准库中提供,并且通过PyPI上的 <a class="reference external" href="https://pypi.org/project/importlib2">importlib2</a> 提供给Python 2。你可能会想写代码来访问例如 <a class="reference internal" href="../library/importlib.html#module-importlib.abc" title="importlib.abc: Abstract base classes related to import"><code class="xref py py-mod docutils literal notranslate"><span class="pre">importlib.abc</span></code></a> 模块,方法如下:</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">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">version_info</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
|
||||
<span class="kn">from</span> <span class="nn">importlib</span> <span class="kn">import</span> <span class="n">abc</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="kn">from</span> <span class="nn">importlib2</span> <span class="kn">import</span> <span class="n">abc</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这段代码的问题是,当Python 4出来的时候会发生什么?最好是将Python 2作为例外情况,而不是Python 3,并假设未来的Python版本与Python 3的兼容性比Python 2更强:</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">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">version_info</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">></span> <span class="mi">2</span><span class="p">:</span>
|
||||
<span class="kn">from</span> <span class="nn">importlib</span> <span class="kn">import</span> <span class="n">abc</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="kn">from</span> <span class="nn">importlib2</span> <span class="kn">import</span> <span class="n">abc</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>不过,最好的解决办法是根本不做版本检测,而是依靠特征检测。这就避免了任何潜在的版本检测错误的问题,并有助于保持你对未来的兼容:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
|
||||
<span class="kn">from</span> <span class="nn">importlib</span> <span class="kn">import</span> <span class="n">abc</span>
|
||||
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
|
||||
<span class="kn">from</span> <span class="nn">importlib2</span> <span class="kn">import</span> <span class="n">abc</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="prevent-compatibility-regressions">
|
||||
<h3>防止兼容性退步<a class="headerlink" href="#prevent-compatibility-regressions" title="永久链接至标题">¶</a></h3>
|
||||
<p>一旦你完全翻译了你的代码,使之与 Python 3 兼容,你将希望确保你的代码不会退步,不会在 Python 3上停止工作。如果你有一个依赖关系阻碍了你目前在Python 3上的实际运行,那就更是如此了。</p>
|
||||
<p>为了帮助保持兼容,你创建的任何新模块都应该在其顶部至少有以下代码块:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">absolute_import</span>
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">division</span>
|
||||
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">print_function</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>你也可以在运行Python 2时使用``-3``标志,对你的代码在执行过程中引发的各种兼容性问题进行警告。如果你用``-Werror``把警告变成错误,那么你可以确保你不会意外地错过一个警告。</p>
|
||||
<p>你也可以使用 <a class="reference external" href="https://pypi.org/project/pylint">Pylint</a> 项目和它的``--py3k``标志来提示你的代码,当你的代码开始偏离 Python 3 的兼容性时,就会收到警告。这也避免了你不得不定期在你的代码上运行 <a class="reference external" href="https://python-modernize.readthedocs.io/">Modernize</a> 或 <a class="reference external" href="http://python-future.org/automatic_conversion.html">Futurize</a> 来捕捉兼容性的退步。这确实要求你只支持Python 2.7和Python 3.4或更新的版本,因为这是Pylint支持的最小Python版本。</p>
|
||||
</section>
|
||||
<section id="check-which-dependencies-block-your-transition">
|
||||
<h3>检查哪些依赖性会阻碍你的过渡<a class="headerlink" href="#check-which-dependencies-block-your-transition" title="永久链接至标题">¶</a></h3>
|
||||
<p>在你使你的代码与 Python 3 兼容**之后**,你应该开始关心你的依赖关系是否也被移植了。 <a class="reference external" href="https://pypi.org/project/caniusepython3">caniusepython3</a> 项目的建立是为了帮助你确定哪些项目——直接或间接地——阻碍了你对Python 3的支持。它既有一个命令行工具,也有一个在https://caniusepython3.com的网页界面。</p>
|
||||
<p>该项目还提供了一些代码,你可以将其集成到你的测试套件中,这样,当你不再有依赖关系阻碍你使用Python 3时,你将有一个失败的测试。这使你不必手动检查你的依赖性,并在你可以开始在Python 3上运行时迅速得到通知。</p>
|
||||
</section>
|
||||
<section id="update-your-setup-py-file-to-denote-python-3-compatibility">
|
||||
<h3>更新你的``setup.py``文件以表示对Python 3的兼容<a class="headerlink" href="#update-your-setup-py-file-to-denote-python-3-compatibility" title="永久链接至标题">¶</a></h3>
|
||||
<p>一旦你的代码在 Python 3 下工作,你应该更新你``setup.py``中的分类器,使其包含``Programming Language :: Python :: 3``并不指定单独的 Python 2 支持。这将告诉使用你的代码的人,你支持Python 2 <strong>和</strong> 3。理想情况下,你也希望为你现在支持的Python的每个主要/次要版本添加分类器。</p>
|
||||
</section>
|
||||
<section id="use-continuous-integration-to-stay-compatible">
|
||||
<h3>使用持续集成以保持兼容<a class="headerlink" href="#use-continuous-integration-to-stay-compatible" title="永久链接至标题">¶</a></h3>
|
||||
<p>一旦你能够完全在Python 3下运行,你将希望确保你的代码总是在Python 2和3下工作。在多个Python解释器下运行测试的最好工具可能是 <a class="reference external" href="https://pypi.org/project/tox">tox</a> 。然后你可以将 tox 与你的持续集成系统集成,这样你就不会意外地破坏对 Python 2 或 3 的支持。</p>
|
||||
<p>你可能还想在 Python 3 解释器中使用``-bb``标志,以便在你将bytes与string或bytes与int进行比较时触发一个异常(后者从 Python 3.5 开始可用)。默认情况下,类型不同的比较只是简单地返回``False``,但是如果你在文本/二进制数据处理或字节的索引分离中犯了一个错误,你就不容易发现这个错误。当这些类型的比较发生时,这个标志会触发一个异常,使错误更容易被发现。</p>
|
||||
<p>基本上就是这样了! 在这一点上,你的代码库同时与 Python 2 和 3 兼容。你的测试也将被设置为不会意外地破坏 Python 2 或 3 的兼容性,无论你在开发时通常在哪个版本下运行测试。</p>
|
||||
</section>
|
||||
<section id="consider-using-optional-static-type-checking">
|
||||
<h3>考虑使用可选的静态类型检查<a class="headerlink" href="#consider-using-optional-static-type-checking" title="永久链接至标题">¶</a></h3>
|
||||
<p>另一个帮助移植你的代码的方法是在你的代码上使用静态类型检查器,如 <a class="reference external" href="http://mypy-lang.org/">mypy</a> 或 <a class="reference external" href="https://github.com/google/pytype">pytype</a>。这些工具可以用来分析你的代码,就像它在Python 2下运行一样,然后你可以第二次运行这个工具,就像你的代码在Python 3下运行一样。通过像这样两次运行静态类型检查器,你可以发现你是否错误地使用了二进制数据类型,例如在Python的一个版本中与另一个版本相比。如果你在你的代码中添加了可选的类型提示,你也可以明确说明你的API是使用文本数据还是二进制数据,这有助于确保在两个版本的Python中所有的功能都符合预期。</p>
|
||||
</section>
|
||||
</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="#">将 Python 2 代码迁移到 Python 3</a><ul>
|
||||
<li><a class="reference internal" href="#the-short-explanation">简要说明</a></li>
|
||||
<li><a class="reference internal" href="#details">详情</a><ul>
|
||||
<li><a class="reference internal" href="#drop-support-for-python-2-6-and-older">删除对Python 2.6及更早版本的支持</a></li>
|
||||
<li><a class="reference internal" href="#make-sure-you-specify-the-proper-version-support-in-your-setup-py-file">确保你在你的``setup.py``文件中指定适当的版本支持</a></li>
|
||||
<li><a class="reference internal" href="#have-good-test-coverage">良好的测试覆盖率</a></li>
|
||||
<li><a class="reference internal" href="#learn-the-differences-between-python-2-3">了解Python 2 和 3之间的区别</a></li>
|
||||
<li><a class="reference internal" href="#update-your-code">更新代码</a><ul>
|
||||
<li><a class="reference internal" href="#division">除法</a></li>
|
||||
<li><a class="reference internal" href="#text-versus-binary-data">文本与二进制数据</a></li>
|
||||
<li><a class="reference internal" href="#use-feature-detection-instead-of-version-detection">使用特征检测而不是版本检测</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#prevent-compatibility-regressions">防止兼容性退步</a></li>
|
||||
<li><a class="reference internal" href="#check-which-dependencies-block-your-transition">检查哪些依赖性会阻碍你的过渡</a></li>
|
||||
<li><a class="reference internal" href="#update-your-setup-py-file-to-denote-python-3-compatibility">更新你的``setup.py``文件以表示对Python 3的兼容</a></li>
|
||||
<li><a class="reference internal" href="#use-continuous-integration-to-stay-compatible">使用持续集成以保持兼容</a></li>
|
||||
<li><a class="reference internal" href="#consider-using-optional-static-type-checking">考虑使用可选的静态类型检查</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="index.html"
|
||||
title="上一章">Python 指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="cporting.html"
|
||||
title="下一章">将扩展模块移植到 Python 3</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/howto/pyporting.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="cporting.html" title="将扩展模块移植到 Python 3"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="index.html" title="Python 指南"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
1152
web/python-docs/howto/regex.html
Normal file
1152
web/python-docs/howto/regex.html
Normal file
File diff suppressed because it is too large
Load Diff
448
web/python-docs/howto/sockets.html
Normal file
448
web/python-docs/howto/sockets.html
Normal file
@@ -0,0 +1,448 @@
|
||||
|
||||
<!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>套接字编程指南 — 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="排序指南" href="sorting.html" />
|
||||
<link rel="prev" title="正则表达式指南" href="regex.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/sockets.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="#">套接字编程指南</a><ul>
|
||||
<li><a class="reference internal" href="#sockets">套接字</a><ul>
|
||||
<li><a class="reference internal" href="#history">历史</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#creating-a-socket">创建套接字</a><ul>
|
||||
<li><a class="reference internal" href="#ipc">进程间通信</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#using-a-socket">使用一个套接字</a><ul>
|
||||
<li><a class="reference internal" href="#binary-data">二进制数据</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#disconnecting">断开连接</a><ul>
|
||||
<li><a class="reference internal" href="#when-sockets-die">套接字何时销毁</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#non-blocking-sockets">非阻塞的套接字</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="regex.html"
|
||||
title="上一章">正则表达式指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="sorting.html"
|
||||
title="下一章">排序指南</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/howto/sockets.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/howto/sockets.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="sorting.html" title="排序指南"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="regex.html" title="正则表达式指南"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="socket-programming-howto">
|
||||
<span id="socket-howto"></span><h1>套接字编程指南<a class="headerlink" href="#socket-programming-howto" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>Gordon McMillan</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="topic">
|
||||
<p class="topic-title">摘要</p>
|
||||
<p>套接字几乎无处不在,但是它却是被误解最严重的技术之一。这是一篇简单的套接字概述。并不是一篇真正的教程 —— 你需要做更多的事情才能让它工作起来。其中也并没有涵盖细节(细节会有很多),但是我希望它能提供足够的背景知识,让你像模像样的开始使用套接字</p>
|
||||
</div>
|
||||
<section id="sockets">
|
||||
<h2>套接字<a class="headerlink" href="#sockets" title="永久链接至标题">¶</a></h2>
|
||||
<p>我将只讨论关于 INET(比如:IPv4 地址族)的套接字,但是它将覆盖几乎 99% 的套接字使用场景。并且我将仅讨论 STREAM(比如:TCP)类型的套接字 - 除非你真的知道你在做什么(那么这篇 HOWTO 可能并不适合你),使用 STREAM 类型的套接字将会得到比其它类型更好的表现与性能。我将尝试揭开套接字的神秘面纱,也会讲到一些阻塞与非阻塞套接字的使用。但是我将以阻塞套接字为起点开始讨论。只有你了解它是如何工作的以后才能处理非阻塞套接字。</p>
|
||||
<p>理解这些东西的难点之一在于「套接字」可以表示很多微妙差异的东西,这取决于上下文。所以首先,让我们先分清楚「客户端」套接字和「服务端」套接字之间的不同,客户端套接字表示对话的一端,服务端套接字更像是总机接线员。客户端程序只能(比如:你的浏览器)使用「客户端」套接字;网络服务器则可以使用「服务端」套接字和「客户端」套接字来会话</p>
|
||||
<section id="history">
|
||||
<h3>历史<a class="headerlink" href="#history" title="永久链接至标题">¶</a></h3>
|
||||
<p>目前为止,在各种形式的 <abbr title="进程间通信">IPC</abbr> 中,套接字是最流行的。在任何指定的平台上,可能会有其它更快的 IPC 形式,但是就跨平台通信来说,套接字大概是唯一的玩法</p>
|
||||
<p>套接字做为 BSD Unix 操作系统的一部分在伯克利诞生,像野火一样在因特网传播。有一个很好的原因 —— 套接字与 INET 的结合使得与世界各地的任意机器间通信变得令人难以置信的简单(至少对比与其他方案来说)</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="creating-a-socket">
|
||||
<h2>创建套接字<a class="headerlink" href="#creating-a-socket" title="永久链接至标题">¶</a></h2>
|
||||
<p>简略地说,当你点击带你来到这个页面的链接时,你的浏览器就已经做了下面这几件事情:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># create an INET, STREAMing socket</span>
|
||||
<span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
|
||||
<span class="c1"># now connect to the web server on port 80 - the normal http port</span>
|
||||
<span class="n">s</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="s2">"www.python.org"</span><span class="p">,</span> <span class="mi">80</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>当连接完成,套接字可以用来发送请求来接收页面上显示的文字。同样是这个套接字也会用来读取响应,最后再被销毁。是的,被销毁了。客户端套接字通常用来做一次交换(或者说一小组序列的交换)。</p>
|
||||
<p>网络服务器发生了什么这个问题就有点复杂了。首页,服务器创建一个「服务端套接字」:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># create an INET, STREAMing socket</span>
|
||||
<span class="n">serversocket</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
|
||||
<span class="c1"># bind the socket to a public host, and a well-known port</span>
|
||||
<span class="n">serversocket</span><span class="o">.</span><span class="n">bind</span><span class="p">((</span><span class="n">socket</span><span class="o">.</span><span class="n">gethostname</span><span class="p">(),</span> <span class="mi">80</span><span class="p">))</span>
|
||||
<span class="c1"># become a server socket</span>
|
||||
<span class="n">serversocket</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>有几件事需要注意:我们使用了 <code class="docutils literal notranslate"><span class="pre">socket.gethostname()</span></code>,所以套接字将外网可见。如果我们使用的是 <code class="docutils literal notranslate"><span class="pre">s.bind(('localhost',</span> <span class="pre">80))</span></code> 或者 <code class="docutils literal notranslate"><span class="pre">s.bind(('127.0.0.1',</span> <span class="pre">80))</span></code>,也会得到一个「服务端」套接字,但是后者只在同一机器上可见。<code class="docutils literal notranslate"><span class="pre">s.bind(('',</span> <span class="pre">80))</span></code> 则指定套接字可以被机器上的任何地址碰巧连接</p>
|
||||
<p>第二个需要注点是:低端口号通常被一些「常用的」服务(HTTP, SNMP 等)所保留。如果你想把程序跑起来,最好使用一个高位端口号(通常是4位的数字)。</p>
|
||||
<p>最后,<code class="docutils literal notranslate"><span class="pre">listen</span></code> 方法的参数会告诉套接字库,我们希望在队列中累积多达 5 个(通常的最大值)连接请求后再拒绝外部连接。 如果所有其他代码都准确无误,这个队列长度应该是足够的。</p>
|
||||
<p>现在我们已经有一个「服务端」套接字,监听了 80 端口,我们可以进入网络服务器的主循环了:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||||
<span class="c1"># accept connections from outside</span>
|
||||
<span class="p">(</span><span class="n">clientsocket</span><span class="p">,</span> <span class="n">address</span><span class="p">)</span> <span class="o">=</span> <span class="n">serversocket</span><span class="o">.</span><span class="n">accept</span><span class="p">()</span>
|
||||
<span class="c1"># now do something with the clientsocket</span>
|
||||
<span class="c1"># in this case, we'll pretend this is a threaded server</span>
|
||||
<span class="n">ct</span> <span class="o">=</span> <span class="n">client_thread</span><span class="p">(</span><span class="n">clientsocket</span><span class="p">)</span>
|
||||
<span class="n">ct</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>事际上,通常有 3 种方法可以让这个循环工作起来 - 调度一个线程来处理 <code class="docutils literal notranslate"><span class="pre">客户端套接字</span></code>,或者把这个应用改成使用非阻塞模式套接字,亦或是使用 <code class="docutils literal notranslate"><span class="pre">select</span></code> 库来实现「服务端」套接字与任意活动 <code class="docutils literal notranslate"><span class="pre">客户端套接字</span></code> 之间的多路复用。稍后会详细介绍。现在最重要的是理解:这就是一个 <em>服务端</em> 套接字做的 <em>所有</em> 事情。它并没有发送任何数据。也没有接收任何数据。它只创建「客户端」套接字。每个 <code class="docutils literal notranslate"><span class="pre">客户端套接字</span></code> 都是为了响应某些其它客户端套接字 <code class="docutils literal notranslate"><span class="pre">connect()</span></code> 到我们绑定的主机。一旦创建 <code class="docutils literal notranslate"><span class="pre">客户端套接字</span></code> 完成,就会返回并监听更多的连接请求。现个客户端可以随意通信 - 它们使用了一些动态分配的端口,会话结束时端口才会被回收</p>
|
||||
<section id="ipc">
|
||||
<h3>进程间通信<a class="headerlink" href="#ipc" title="永久链接至标题">¶</a></h3>
|
||||
<p>如果你需要在同一台机器上进行两个进程间的快速 IPC 通信,你应该了解管道或者共享内存。如果你决定使用 AF_INET 类型的套接字,绑定「服务端」套接字到 <code class="docutils literal notranslate"><span class="pre">'localhost'</span></code> 。在大多数平台,这将会使用一个许多网络层间的通用快捷方式(本地回环地址)并且速度会快很多</p>
|
||||
<div class="admonition seealso">
|
||||
<p class="admonition-title">参见</p>
|
||||
<p><a class="reference internal" href="../library/multiprocessing.html#module-multiprocessing" title="multiprocessing: Process-based parallelism."><code class="xref py py-mod docutils literal notranslate"><span class="pre">multiprocessing</span></code></a> 模块使跨平台 IPC 通信成为一个高层的 API</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="using-a-socket">
|
||||
<h2>使用一个套接字<a class="headerlink" href="#using-a-socket" title="永久链接至标题">¶</a></h2>
|
||||
<p>首先需要注意,浏览器的「客户端」套接字和网络服务器的「客户端」套接字是极为相似的。即这种会话是「点对点」的。或者也可以说 <em>你作为设计师需要自行决定会话的规则和礼节</em> 。通常情况下,<code class="docutils literal notranslate"><span class="pre">连接</span></code> 套接字通过发送一个请求或者信号来开始一次会话。但这属于设计决定,并不是套接字规则。</p>
|
||||
<p>现在有两组用于通信的动词。你可以使用 <code class="docutils literal notranslate"><span class="pre">send</span></code> 和 <code class="docutils literal notranslate"><span class="pre">recv</span></code> ,或者你可以把客户端套接字改成文件类型的形式来使用 <code class="docutils literal notranslate"><span class="pre">read</span></code> 和 <code class="docutils literal notranslate"><span class="pre">write</span></code> 方法。后者是 Java 语言中表示套接字的方法,我将不会在这儿讨论这个,但是要提醒你需要调用套接字的 <code class="docutils literal notranslate"><span class="pre">flush</span></code> 方法。这些是“缓冲”的文件,一个经常出现的错误是 <code class="docutils literal notranslate"><span class="pre">write</span></code> 一些东西,然后就直接开始 <code class="docutils literal notranslate"><span class="pre">read</span></code> 一个响应。如果不调用 <code class="docutils literal notranslate"><span class="pre">flush</span></code> ,你可能会一直等待这个响应,因为请求可能还在你的输出缓冲中。</p>
|
||||
<p>现在我来到了套接字的两个主要的绊脚石 - <code class="docutils literal notranslate"><span class="pre">send</span></code> 和 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 操作网络缓冲区。它们并不一定可以处理所有你想要(期望)的字节,因为它们主要关注点是处理网络缓冲。通常,它们在关联的网络缓冲区 <code class="docutils literal notranslate"><span class="pre">send</span></code> 或者清空 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 时返回。然后告诉你处理了多少个字节。<em>你</em> 的责任是一直调用它们直到你所有的消息处理完成。</p>
|
||||
<p>当 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 方法返回 0 字节时,就表示另一端已经关闭(或者它所在的进程关闭)了连接。你再也不能从这个连接上获取到任何数据了。你可以成功的发送数据;我将在后面讨论这一点。</p>
|
||||
<p>像 HTTP 这样的协议只使用一个套接字进行一次传输。客户端发送一个请求,然后读取响应。就这么简单。套接字会被销毁。 表示客户端可以通过接收 0 字节序列表示检测到响应的结束。</p>
|
||||
<p>但是如果你打算在随后来的传输中复用套接字的话,你需要明白 <em>套接字里面是不存在 :abbr:`EOT (传输结束)`</em> 的。重复一下:套接字 <code class="docutils literal notranslate"><span class="pre">send</span></code> 或者 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 完 0 字节后返回,连接会中断。如果连接没有被断开,你可能会永远处于等待 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 的状态,因为(就目前来说)套接字 <em>不会</em> 告诉你不用再读取了。现在如果你细心一点,你可能会意识到套接字基本事实:<em>消息必须要么具有固定长度,要么可以界定,要么指定了长度(比较好的做法),要么以关闭连接为结束</em>。选择完全由你而定(这比让别人定更合理)。</p>
|
||||
<p>假定你不希望结束连接,那么最简单的解决方案就是使用定长消息:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MySocket</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""demonstration class only</span>
|
||||
<span class="sd"> - coded for clarity, not efficiency</span>
|
||||
<span class="sd"> """</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">sock</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">sock</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span>
|
||||
<span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">sock</span> <span class="o">=</span> <span class="n">sock</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">sock</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">mysend</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
|
||||
<span class="n">totalsent</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="n">totalsent</span> <span class="o"><</span> <span class="n">MSGLEN</span><span class="p">:</span>
|
||||
<span class="n">sent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sock</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">msg</span><span class="p">[</span><span class="n">totalsent</span><span class="p">:])</span>
|
||||
<span class="k">if</span> <span class="n">sent</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"socket connection broken"</span><span class="p">)</span>
|
||||
<span class="n">totalsent</span> <span class="o">=</span> <span class="n">totalsent</span> <span class="o">+</span> <span class="n">sent</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">myreceive</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="n">chunks</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="n">bytes_recd</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="n">bytes_recd</span> <span class="o"><</span> <span class="n">MSGLEN</span><span class="p">:</span>
|
||||
<span class="n">chunk</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="nb">min</span><span class="p">(</span><span class="n">MSGLEN</span> <span class="o">-</span> <span class="n">bytes_recd</span><span class="p">,</span> <span class="mi">2048</span><span class="p">))</span>
|
||||
<span class="k">if</span> <span class="n">chunk</span> <span class="o">==</span> <span class="sa">b</span><span class="s1">''</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"socket connection broken"</span><span class="p">)</span>
|
||||
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">chunk</span><span class="p">)</span>
|
||||
<span class="n">bytes_recd</span> <span class="o">=</span> <span class="n">bytes_recd</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="n">chunk</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="sa">b</span><span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">chunks</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>发送分部代码几乎可用于任何消息传递方案 —— 在 Python 中你发送字符串,可以使用 <code class="docutils literal notranslate"><span class="pre">len()</span></code> 方法来确定它的长度(即使它嵌入了 <code class="docutils literal notranslate"><span class="pre">\0</span></code> 字符),主要是接收代码变得更复杂。(在 C 语言中,并没有更糟糕,除非消息嵌入了 <code class="docutils literal notranslate"><span class="pre">\0</span></code> 字符而且你又无法使用 <code class="docutils literal notranslate"><span class="pre">strlen</span></code> )</p>
|
||||
<p>最简单的改进是让消息的第一个字符表示消息类型,由类型决定长度。现在你需要两次 <code class="docutils literal notranslate"><span class="pre">recv</span></code>- 第一次取(至少)第一个字符来知晓长度,第二次在循环中获取剩余所有的消息。如果你决定到分界线,你将收到一些任意大小的块,(4096 或者 8192 通常是比较合适的网络缓冲区大小),扫描你接收到的分界符</p>
|
||||
<p>一个需要意识到的复杂情况是:如果你的会话协议允许多个消息被发送回来(没有响应),调用 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 传入任意大小的块,你可能会因为读到后续接收的消息而停止读取。你需要将它放在一边并保存,直到它需要为止。</p>
|
||||
<p>以其长度(例如,作为5个数字字符)作为消息前缀时会变得更复杂,因为(信不信由你)你可能无法在一个 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 中获得所有5个字符。在一般使用时,你会侥幸避免该状况;但是在高网络负载中,除非你使用两个 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 循环,否则你的代码将很快中断 —— 第一个用于确定长度,第二个用于获取消息的数据部分。这很讨厌。当你发现 <code class="docutils literal notranslate"><span class="pre">send</span></code> 并不总是设法在支持搞定一切时,你也会有这种感觉。 尽管已经阅读过这篇文章,但最终还是会有所了解!</p>
|
||||
<p>限于篇幅,建立你的角色,(保持与我的竞争位置),这些改进将留给读者做为练习。现在让我们继续。</p>
|
||||
<section id="binary-data">
|
||||
<h3>二进制数据<a class="headerlink" href="#binary-data" title="永久链接至标题">¶</a></h3>
|
||||
<p>通过套接字传送二进制数据是可行的。主要问题在于并非所有机器都用同样的二进制数据格式。比如 Motorola 芯片用两个十六进制字节 00 01 来表示一个 16 位整数值 1。而 Intel 和 DEC 则会做字节反转 —— 即用 01 00 来表示 1。套接字库要求转换 16 位和 32 位整数 —— <code class="docutils literal notranslate"><span class="pre">ntohl,</span> <span class="pre">htonl,</span> <span class="pre">ntohs,</span> <span class="pre">htons</span></code> 其中的「n」表示 <em>network</em>,「h」表示 <em>host</em>,「s」表示 <em>short</em>,「l」表示 <em>long</em>。在网络序列就是主机序列时它们什么都不做,但是如果机器是字节反转的则会适当地交换字节序。</p>
|
||||
<p>在现今的 32 位机器中,二进制数据的 ascii 表示往往比二进制表示要小。这是因为在非常多的时候所有 long 的值均为 0 或者 1。字符串形式的 "0" 为两个字节,而二进制形式则为四个。当然这不适用于固定长度的信息。自行决定,请自行决定。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="disconnecting">
|
||||
<h2>断开连接<a class="headerlink" href="#disconnecting" title="永久链接至标题">¶</a></h2>
|
||||
<p>严格地讲,你应该在 <code class="docutils literal notranslate"><span class="pre">close</span></code> 它之前将套接字 <code class="docutils literal notranslate"><span class="pre">shutdown</span></code> 。 <code class="docutils literal notranslate"><span class="pre">shutdown</span></code> 是发送给套接字另一端的一种建议。调用时参数不同意义也不一样,它可能意味着「我不会再发送了,但我仍然会监听」,或者「我没有监听了,真棒!」。然而,大多数套接字库或者程序员都习惯了忽略使用这种礼节,因为通常情况下 <code class="docutils literal notranslate"><span class="pre">close</span></code> 与 <code class="docutils literal notranslate"><span class="pre">shutdown();</span> <span class="pre">close()</span></code> 是一样的。所以在大多数情况下,不需要显式的 <code class="docutils literal notranslate"><span class="pre">shutdown</span></code> 。</p>
|
||||
<p>高效使用 <code class="docutils literal notranslate"><span class="pre">shutdown</span></code> 的一种方法是在类似 HTTP 的交换中。客户端发送请求,然后执行 <code class="docutils literal notranslate"><span class="pre">shutdown(1)</span></code> 。 这告诉服务器“此客户端已完成发送,但仍可以接收”。服务器可以通过接收 0 字节来检测 “EOF” 。它可以假设它有完整的请求。服务器发送回复。如果 <code class="docutils literal notranslate"><span class="pre">send</span></code> 成功完成,那么客户端仍在接收。</p>
|
||||
<p>Python 进一步自动关闭,并说当一个套接字被垃圾收集时,如果需要它会自动执行 <code class="docutils literal notranslate"><span class="pre">close</span></code> 。但依靠这个机制是一个非常坏的习惯。如果你的套接字在没有 <code class="docutils literal notranslate"><span class="pre">close</span></code> 的情况下就消失了,那么另一端的套接字可能会无限期地挂起,以为你只是慢了一步。完成后 <em>请</em> <code class="docutils literal notranslate"><span class="pre">close</span></code> 你的套接字。</p>
|
||||
<section id="when-sockets-die">
|
||||
<h3>套接字何时销毁<a class="headerlink" href="#when-sockets-die" title="永久链接至标题">¶</a></h3>
|
||||
<p>使用阻塞套接字最糟糕的事情可能就是当另一边下线时(没有 <code class="docutils literal notranslate"><span class="pre">close</span></code> )会发生什么。你的套接字可能会挂起。 TCP 是一种可靠的协议,它会在放弃连接之前等待很长时间。如果你正在使用线程,那么整个线程基本上已经死了。你无能为力。只要你没有做一些愚蠢的事情,比如在进行阻塞读取时持有一个锁,那么线程并没有真正消耗掉资源。 <em>不要</em> 尝试杀死线程 —— 线程比进程更有效的部分原因是它们避免了与自动回收资源相关的开销。换句话说,如果你设法杀死线程,你的整个进程很可能被搞坏。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="non-blocking-sockets">
|
||||
<h2>非阻塞的套接字<a class="headerlink" href="#non-blocking-sockets" title="永久链接至标题">¶</a></h2>
|
||||
<p>如果你已理解上述内容,那么你已经了解了使用套接字的机制所需了解的大部分内容。你仍将以相同的方式使用相同的函数调用。 只是,如果你做得对,你的应用程序几乎是由内到外的。</p>
|
||||
<p>在 Python 中是使用 <code class="docutils literal notranslate"><span class="pre">socket.setblocking(0)</span></code> 来使其为非阻塞。 在 C 中做法更为复杂(例如,你需要在 BSD 风格的 <code class="docutils literal notranslate"><span class="pre">O_NONBLOCK</span></code> 和几乎无区别的 POSIX 风格的 <code class="docutils literal notranslate"><span class="pre">O_NDELAY</span></code> 之间作出选择,这与 <code class="docutils literal notranslate"><span class="pre">TCP_NODELAY</span></code> 完全不一样。)。 但其思路是完全相同的。 你要在创建套拼字之后但在使用它之前执行此操作。 (实际上,除非你是疯子才会反复切换。)</p>
|
||||
<p>主要的机制差异是 <code class="docutils literal notranslate"><span class="pre">send</span></code> 、 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 、 <code class="docutils literal notranslate"><span class="pre">connect</span></code> 和 <code class="docutils literal notranslate"><span class="pre">accept</span></code> 可以在没有做任何事情的情况下返回。 你(当然)有很多选择。你可以检查返回代码和错误代码,通常会让自己发疯。如果你不相信我,请尝试一下。你的应用程序将变得越来越大、越来越 Bug 、吸干 CPU。因此,让我们跳过脑死亡的解决方案并做正确的事。</p>
|
||||
<p>使用 <code class="docutils literal notranslate"><span class="pre">select</span></code> 库</p>
|
||||
<p>在 C 中,编码 <code class="docutils literal notranslate"><span class="pre">select</span></code> 相当复杂。 在 Python 中,它是很简单,但它与 C 版本足够接近,如果你在 Python 中理解 <code class="docutils literal notranslate"><span class="pre">select</span></code> ,那么在 C 中你会几乎不会遇到麻烦:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">ready_to_read</span><span class="p">,</span> <span class="n">ready_to_write</span><span class="p">,</span> <span class="n">in_error</span> <span class="o">=</span> \
|
||||
<span class="n">select</span><span class="o">.</span><span class="n">select</span><span class="p">(</span>
|
||||
<span class="n">potential_readers</span><span class="p">,</span>
|
||||
<span class="n">potential_writers</span><span class="p">,</span>
|
||||
<span class="n">potential_errs</span><span class="p">,</span>
|
||||
<span class="n">timeout</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>你传递给 <code class="docutils literal notranslate"><span class="pre">select</span></code> 三个列表:第一个包含你可能想要尝试读取的所有套接字;第二个是你可能想要尝试写入的所有套接字,以及要检查错误的最后一个(通常为空)。你应该注意,套接字可以进入多个列表。 <code class="docutils literal notranslate"><span class="pre">select</span></code> 调用是阻塞的,但你可以给它一个超时。这通常是一件明智的事情 —— 给它一个很长的超时(比如一分钟),除非你有充分的理由不这样做。</p>
|
||||
<p>作为返回,你将获得三个列表。它们包含实际可读、可写和有错误的套接字。 这些列表中的每一个都是你传入的相应列表的子集(可能为空)。</p>
|
||||
<p>如果一个套接字在输出可读列表中,那么你可以像我们一样接近这个业务,那个套接字上的 <code class="docutils literal notranslate"><span class="pre">recv</span></code> 将返回 <em>一些内容</em> 。可写列表的也相同,你将能够发送 <em>一些内容</em> 。 也许不是你想要的全部,但 <em>有些东西</em> 比没有东西更好。 (实际上,任何合理健康的套接字都将以可写方式返回 —— 它只是意味着出站网络缓冲区空间可用。)</p>
|
||||
<p>如果你有一个“服务器”套接字,请将其放在 potential_readers 列表中。如果它出现在可读列表中,那么你的 <code class="docutils literal notranslate"><span class="pre">accept</span></code> (几乎肯定)会起作用。如果你已经创建了一个新的套接字 <code class="docutils literal notranslate"><span class="pre">connect</span></code> 其他人,请将它放在 potential_writers 列表中。如果它出现在可写列表中,那么它有可能已连接。</p>
|
||||
<p>实际上,即使使用阻塞套接字, <code class="docutils literal notranslate"><span class="pre">select</span></code> 也很方便。这是确定是否阻塞的一种方法 —— 当缓冲区中存在某些内容时,套接字返回为可读。然而,这仍然无助于确定另一端是否完成或者只是忙于其他事情的问题。</p>
|
||||
<p><strong>可移植性警告</strong> :在 Unix 上, <code class="docutils literal notranslate"><span class="pre">select</span></code> 适用于套接字和文件。 不要在 Windows 上尝试。在 Windows 上, <code class="docutils literal notranslate"><span class="pre">select</span></code> 仅适用于套接字。另请注意,在 C 中,许多更高级的套接字选项在 Windows 上的执行方式不同。事实上,在 Windows 上我通常在使用我的套接字使用线程(非常非常好)。</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="#">套接字编程指南</a><ul>
|
||||
<li><a class="reference internal" href="#sockets">套接字</a><ul>
|
||||
<li><a class="reference internal" href="#history">历史</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#creating-a-socket">创建套接字</a><ul>
|
||||
<li><a class="reference internal" href="#ipc">进程间通信</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#using-a-socket">使用一个套接字</a><ul>
|
||||
<li><a class="reference internal" href="#binary-data">二进制数据</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#disconnecting">断开连接</a><ul>
|
||||
<li><a class="reference internal" href="#when-sockets-die">套接字何时销毁</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#non-blocking-sockets">非阻塞的套接字</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="regex.html"
|
||||
title="上一章">正则表达式指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="sorting.html"
|
||||
title="下一章">排序指南</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/howto/sockets.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="sorting.html" title="排序指南"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="regex.html" title="正则表达式指南"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
517
web/python-docs/howto/sorting.html
Normal file
517
web/python-docs/howto/sorting.html
Normal file
@@ -0,0 +1,517 @@
|
||||
|
||||
<!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>排序指南 — 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="Unicode 指南" href="unicode.html" />
|
||||
<link rel="prev" title="套接字编程指南" href="sockets.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/sorting.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="#">排序指南</a><ul>
|
||||
<li><a class="reference internal" href="#sorting-basics">排序的基础知识</a></li>
|
||||
<li><a class="reference internal" href="#key-functions">键函数</a></li>
|
||||
<li><a class="reference internal" href="#operator-module-functions">Operator 模块函数</a></li>
|
||||
<li><a class="reference internal" href="#ascending-and-descending">升序与降序</a></li>
|
||||
<li><a class="reference internal" href="#sort-stability-and-complex-sorts">排序稳定性与复杂排序</a></li>
|
||||
<li><a class="reference internal" href="#the-old-way-using-decorate-sort-undecorate">使用装饰-排序-去装饰的旧方法</a></li>
|
||||
<li><a class="reference internal" href="#the-old-way-using-the-cmp-parameter">使用 <em>cmp</em> 参数的旧方法</a></li>
|
||||
<li><a class="reference internal" href="#odd-and-ends">其它</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="sockets.html"
|
||||
title="上一章">套接字编程指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="unicode.html"
|
||||
title="下一章">Unicode 指南</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/howto/sorting.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/howto/sorting.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="unicode.html" title="Unicode 指南"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="sockets.html" title="套接字编程指南"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="sorting-how-to">
|
||||
<span id="sortinghowto"></span><h1>排序指南<a class="headerlink" href="#sorting-how-to" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p>Andrew Dalke 与 Raymond Hettinger</p>
|
||||
</dd>
|
||||
<dt class="field-even">发布版本</dt>
|
||||
<dd class="field-even"><p>0.1</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>内置列表方法 <a class="reference internal" href="../library/stdtypes.html#list.sort" title="list.sort"><code class="xref py py-meth docutils literal notranslate"><span class="pre">list.sort()</span></code></a> 原地修改列表,而内置函数 <a class="reference internal" href="../library/functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal notranslate"><span class="pre">sorted()</span></code></a> 由可迭代对象新建有序列表。</p>
|
||||
<p>在本文档中,我们将探索使用 Python 对数据进行排序的各种技术。</p>
|
||||
<section id="sorting-basics">
|
||||
<h2>排序的基础知识<a class="headerlink" href="#sorting-basics" title="永久链接至标题">¶</a></h2>
|
||||
<p>简单的升序排序非常简单:只需调用 <a class="reference internal" href="../library/functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal notranslate"><span class="pre">sorted()</span></code></a> 函数即可。它会返回一个新的已排序列表。</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">([</span><span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">])</span>
|
||||
<span class="go">[1, 2, 3, 4, 5]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>亦可用 <a class="reference internal" href="../library/stdtypes.html#list.sort" title="list.sort"><code class="xref py py-meth docutils literal notranslate"><span class="pre">list.sort()</span></code></a> 方法。它原地修改原列表(并返回 <code class="docutils literal notranslate"><span class="pre">None</span></code> 以避免混淆)。往往不如 <a class="reference internal" href="../library/functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal notranslate"><span class="pre">sorted()</span></code></a> 方便——但若不需原列表,用它会略高效些。</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
|
||||
<span class="gp">>>> </span><span class="n">a</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
|
||||
<span class="gp">>>> </span><span class="n">a</span>
|
||||
<span class="go">[1, 2, 3, 4, 5]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>另一个区别是 <a class="reference internal" href="../library/stdtypes.html#list.sort" title="list.sort"><code class="xref py py-meth docutils literal notranslate"><span class="pre">list.sort()</span></code></a> 方法只为列表定义,而 <a class="reference internal" href="../library/functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal notranslate"><span class="pre">sorted()</span></code></a> 函数接受任何可迭代对象。</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">({</span><span class="mi">1</span><span class="p">:</span> <span class="s1">'D'</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s1">'B'</span><span class="p">,</span> <span class="mi">3</span><span class="p">:</span> <span class="s1">'B'</span><span class="p">,</span> <span class="mi">4</span><span class="p">:</span> <span class="s1">'E'</span><span class="p">,</span> <span class="mi">5</span><span class="p">:</span> <span class="s1">'A'</span><span class="p">})</span>
|
||||
<span class="go">[1, 2, 3, 4, 5]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="key-functions">
|
||||
<h2>键函数<a class="headerlink" href="#key-functions" title="永久链接至标题">¶</a></h2>
|
||||
<p><a class="reference internal" href="../library/stdtypes.html#list.sort" title="list.sort"><code class="xref py py-meth docutils literal notranslate"><span class="pre">list.sort()</span></code></a> 和 <a class="reference internal" href="../library/functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal notranslate"><span class="pre">sorted()</span></code></a> 都有一个 <em>key</em> 形参来指定在进行比较之前要在每个列表元素上进行调用的函数。</p>
|
||||
<p>例如,这是个不区分大小写的字符串比较:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="s2">"This is a test string from Andrew"</span><span class="o">.</span><span class="n">split</span><span class="p">(),</span> <span class="n">key</span><span class="o">=</span><span class="nb">str</span><span class="o">.</span><span class="n">lower</span><span class="p">)</span>
|
||||
<span class="go">['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><em>key</em> 形参的值应该是一个函数,它接受一个参数并并返回一个用于排序的键。这种技巧速度很快,因为对于每个输入记录只会调用一次 key 函数。</p>
|
||||
<p>常见的模式是用对象的某一些索引作为键对复杂对象排序。例如:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">student_tuples</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="gp">... </span> <span class="p">(</span><span class="s1">'john'</span><span class="p">,</span> <span class="s1">'A'</span><span class="p">,</span> <span class="mi">15</span><span class="p">),</span>
|
||||
<span class="gp">... </span> <span class="p">(</span><span class="s1">'jane'</span><span class="p">,</span> <span class="s1">'B'</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span>
|
||||
<span class="gp">... </span> <span class="p">(</span><span class="s1">'dave'</span><span class="p">,</span> <span class="s1">'B'</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span>
|
||||
<span class="gp">... </span><span class="p">]</span>
|
||||
<span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_tuples</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">student</span><span class="p">:</span> <span class="n">student</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="c1"># sort by age</span>
|
||||
<span class="go">[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>同样的方法对于有具名属性的对象也适用。例如:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">class</span> <span class="nc">Student</span><span class="p">:</span>
|
||||
<span class="gp">... </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">name</span><span class="p">,</span> <span class="n">grade</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
|
||||
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">grade</span> <span class="o">=</span> <span class="n">grade</span>
|
||||
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">age</span> <span class="o">=</span> <span class="n">age</span>
|
||||
<span class="gp">... </span> <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="k">return</span> <span class="nb">repr</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">grade</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">age</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">student_objects</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="gp">... </span> <span class="n">Student</span><span class="p">(</span><span class="s1">'john'</span><span class="p">,</span> <span class="s1">'A'</span><span class="p">,</span> <span class="mi">15</span><span class="p">),</span>
|
||||
<span class="gp">... </span> <span class="n">Student</span><span class="p">(</span><span class="s1">'jane'</span><span class="p">,</span> <span class="s1">'B'</span><span class="p">,</span> <span class="mi">12</span><span class="p">),</span>
|
||||
<span class="gp">... </span> <span class="n">Student</span><span class="p">(</span><span class="s1">'dave'</span><span class="p">,</span> <span class="s1">'B'</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span>
|
||||
<span class="gp">... </span><span class="p">]</span>
|
||||
<span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_objects</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">student</span><span class="p">:</span> <span class="n">student</span><span class="o">.</span><span class="n">age</span><span class="p">)</span> <span class="c1"># sort by age</span>
|
||||
<span class="go">[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="operator-module-functions">
|
||||
<h2>Operator 模块函数<a class="headerlink" href="#operator-module-functions" title="永久链接至标题">¶</a></h2>
|
||||
<p>上面显示的键函数模式非常常见,因此 Python 提供了便利功能,使访问器功能更容易,更快捷。 <a class="reference internal" href="../library/operator.html#module-operator" title="operator: Functions corresponding to the standard operators."><code class="xref py py-mod docutils literal notranslate"><span class="pre">operator</span></code></a> 模块有 <a class="reference internal" href="../library/operator.html#operator.itemgetter" title="operator.itemgetter"><code class="xref py py-func docutils literal notranslate"><span class="pre">itemgetter()</span></code></a> 、 <a class="reference internal" href="../library/operator.html#operator.attrgetter" title="operator.attrgetter"><code class="xref py py-func docutils literal notranslate"><span class="pre">attrgetter()</span></code></a> 和 <a class="reference internal" href="../library/operator.html#operator.methodcaller" title="operator.methodcaller"><code class="xref py py-func docutils literal notranslate"><span class="pre">methodcaller()</span></code></a> 函数。</p>
|
||||
<p>用了那些函数之后,前面的示例变得更简单,运行起来也更快:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">operator</span> <span class="kn">import</span> <span class="n">itemgetter</span><span class="p">,</span> <span class="n">attrgetter</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_tuples</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span>
|
||||
<span class="go">[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_objects</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">attrgetter</span><span class="p">(</span><span class="s1">'age'</span><span class="p">))</span>
|
||||
<span class="go">[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>运算符模块的函数可以用来作多级排序。例如,按 <em>grade</em> 排序,然后按 <em>age</em> 排序:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_tuples</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
|
||||
<span class="go">[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_objects</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">attrgetter</span><span class="p">(</span><span class="s1">'grade'</span><span class="p">,</span> <span class="s1">'age'</span><span class="p">))</span>
|
||||
<span class="go">[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="ascending-and-descending">
|
||||
<h2>升序与降序<a class="headerlink" href="#ascending-and-descending" title="永久链接至标题">¶</a></h2>
|
||||
<p><a class="reference internal" href="../library/stdtypes.html#list.sort" title="list.sort"><code class="xref py py-meth docutils literal notranslate"><span class="pre">list.sort()</span></code></a> 和 <a class="reference internal" href="../library/functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal notranslate"><span class="pre">sorted()</span></code></a> 接受布尔形参 <em>reverse</em> 用于标记降序排序。例如,将学生数据按 <em>age</em> 倒序排序:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_tuples</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="go">[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_objects</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">attrgetter</span><span class="p">(</span><span class="s1">'age'</span><span class="p">),</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="go">[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="sort-stability-and-complex-sorts">
|
||||
<h2>排序稳定性与复杂排序<a class="headerlink" href="#sort-stability-and-complex-sorts" title="永久链接至标题">¶</a></h2>
|
||||
<p>排序保证 <a class="reference external" href="https://en.wikipedia.org/wiki/Sorting_algorithm#Stability">稳定</a>:等键记录保持原始顺序。</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="p">[(</span><span class="s1">'red'</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="s1">'blue'</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="s1">'red'</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s1">'blue'</span><span class="p">,</span> <span class="mi">2</span><span class="p">)]</span>
|
||||
<span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span>
|
||||
<span class="go">[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>注意 <em>blue</em> 的两个记录是如何保序的:<code class="docutils literal notranslate"><span class="pre">('blue',</span> <span class="pre">1)</span></code> 保证先于 <code class="docutils literal notranslate"><span class="pre">('blue',</span> <span class="pre">2)</span></code>。</p>
|
||||
<p>这个了不起的特性使得借助一系列排序步骤构建出复杂排序成为可能。例如,要按 <em>grade</em> 降序后 <em>age</em> 升序排序学生数据,只需先用 <em>age</em> 排序再用 <em>grade</em> 排序即可:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">s</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">student_objects</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">attrgetter</span><span class="p">(</span><span class="s1">'age'</span><span class="p">))</span> <span class="c1"># sort on secondary key</span>
|
||||
<span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">attrgetter</span><span class="p">(</span><span class="s1">'grade'</span><span class="p">),</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># now sort on primary key, descending</span>
|
||||
<span class="go">[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>可抽象为包装函数,依据接收的一些字段序的元组对接收的列表做多趟排序。</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">def</span> <span class="nf">multisort</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">specs</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">reverse</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">specs</span><span class="p">):</span>
|
||||
<span class="gp">... </span> <span class="n">xs</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="n">attrgetter</span><span class="p">(</span><span class="n">key</span><span class="p">),</span> <span class="n">reverse</span><span class="o">=</span><span class="n">reverse</span><span class="p">)</span>
|
||||
<span class="gp">... </span> <span class="k">return</span> <span class="n">xs</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">multisort</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">student_objects</span><span class="p">),</span> <span class="p">((</span><span class="s1">'grade'</span><span class="p">,</span> <span class="kc">True</span><span class="p">),</span> <span class="p">(</span><span class="s1">'age'</span><span class="p">,</span> <span class="kc">False</span><span class="p">)))</span>
|
||||
<span class="go">[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Python 中曾用的 <a class="reference external" href="https://en.wikipedia.org/wiki/Timsort">Timsort</a> 算法借助数据集中任何已有的有序性来高效进行多种排序。</p>
|
||||
</section>
|
||||
<section id="the-old-way-using-decorate-sort-undecorate">
|
||||
<h2>使用装饰-排序-去装饰的旧方法<a class="headerlink" href="#the-old-way-using-decorate-sort-undecorate" title="永久链接至标题">¶</a></h2>
|
||||
<p>装饰-排序-去装饰 (Decorate-Sort-Undecorate) 得名于它的三个步骤:</p>
|
||||
<ul class="simple">
|
||||
<li><p>首先,用控制排序顺序的新值装饰初始列表。</p></li>
|
||||
<li><p>其次,排序装饰后的列表。</p></li>
|
||||
<li><p>最后,去除装饰即得按新顺序排列的初始值的列表。</p></li>
|
||||
</ul>
|
||||
<p>例如,用 DSU 方法按 <em>grade</em> 排序学生数据:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">decorated</span> <span class="o">=</span> <span class="p">[(</span><span class="n">student</span><span class="o">.</span><span class="n">grade</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">student</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">student</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">student_objects</span><span class="p">)]</span>
|
||||
<span class="gp">>>> </span><span class="n">decorated</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
|
||||
<span class="gp">>>> </span><span class="p">[</span><span class="n">student</span> <span class="k">for</span> <span class="n">grade</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">student</span> <span class="ow">in</span> <span class="n">decorated</span><span class="p">]</span> <span class="c1"># undecorate</span>
|
||||
<span class="go">[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这方法语有效是因为元组按字典顺序进行比较,先比较第一项;如果它们相同则比较第二个项目,依此类推。</p>
|
||||
<p>不一定在所有情况下都要在装饰列表中包含索引 <em>i</em> ,但包含它有两个好处:</p>
|
||||
<ul class="simple">
|
||||
<li><p>排序是稳定的——如果两个项具有相同的键,它们的顺序将保留在排序列表中。</p></li>
|
||||
<li><p>原始项目不必具有可比性,因为装饰元组的排序最多由前两项决定。 因此,例如原始列表可能包含无法直接排序的复数。</p></li>
|
||||
</ul>
|
||||
<p>这个方法的另一个名字是 Randal L. Schwartz 在 Perl 程序员中推广的 <a class="reference external" href="https://en.wikipedia.org/wiki/Schwartzian_transform">Schwartzian transform</a>。</p>
|
||||
<p>既然 Python 排序提供了键函数,那么通常不需要这种技术。</p>
|
||||
</section>
|
||||
<section id="the-old-way-using-the-cmp-parameter">
|
||||
<h2>使用 <em>cmp</em> 参数的旧方法<a class="headerlink" href="#the-old-way-using-the-cmp-parameter" title="永久链接至标题">¶</a></h2>
|
||||
<p>本 HOWTO 中给出的许多结构都假定为 Python 2.4 或更高版本。在此之前,没有内置 <a class="reference internal" href="../library/functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal notranslate"><span class="pre">sorted()</span></code></a> , <a class="reference internal" href="../library/stdtypes.html#list.sort" title="list.sort"><code class="xref py py-meth docutils literal notranslate"><span class="pre">list.sort()</span></code></a> 也没有关键字参数。相反,所有 Py2.x 版本都支持 <em>cmp</em> 参数来处理用户指定的比较函数。</p>
|
||||
<p>在 Py3.0 中, <em>cmp</em> 参数被完全删除(作为简化和统一语言努力的一部分,消除了丰富的比较与 <code class="xref py py-meth docutils literal notranslate"><span class="pre">__cmp__()</span></code> 魔术方法之间的冲突)。</p>
|
||||
<p>在 Py2.x 中, sort 允许一个可选函数,可以调用它来进行比较。该函数应该采用两个参数进行比较,然后返回负值为小于,如果它们相等则返回零,或者返回大于大于的正值。例如,我们可以这样做:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">def</span> <span class="nf">numeric_compare</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">return</span> <span class="n">x</span> <span class="o">-</span> <span class="n">y</span>
|
||||
<span class="gp">>>> </span><span class="nb">sorted</span><span class="p">([</span><span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="n">cmp</span><span class="o">=</span><span class="n">numeric_compare</span><span class="p">)</span>
|
||||
<span class="go">[1, 2, 3, 4, 5]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>或者你可反转比较的顺序:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">def</span> <span class="nf">reverse_numeric</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">return</span> <span class="n">y</span> <span class="o">-</span> <span class="n">x</span>
|
||||
<span class="gp">>>> </span><span class="nb">sorted</span><span class="p">([</span><span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="n">cmp</span><span class="o">=</span><span class="n">reverse_numeric</span><span class="p">)</span>
|
||||
<span class="go">[5, 4, 3, 2, 1]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>将代码从 Python 2.x 移植到 3.x 时,如果用户提供比较功能并且需要将其转换为键函数,则会出现这种情况。 以下包装器使这很容易:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">cmp_to_key</span><span class="p">(</span><span class="n">mycmp</span><span class="p">):</span>
|
||||
<span class="s1">'Convert a cmp= function into a key= function'</span>
|
||||
<span class="k">class</span> <span class="nc">K</span><span class="p">:</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">obj</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="n">obj</span>
|
||||
<span class="k">def</span> <span class="fm">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">mycmp</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span>
|
||||
<span class="k">def</span> <span class="fm">__gt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">mycmp</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span>
|
||||
<span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">mycmp</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span>
|
||||
<span class="k">def</span> <span class="fm">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">mycmp</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span> <span class="o"><=</span> <span class="mi">0</span>
|
||||
<span class="k">def</span> <span class="fm">__ge__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">mycmp</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">0</span>
|
||||
<span class="k">def</span> <span class="fm">__ne__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">mycmp</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span>
|
||||
<span class="k">return</span> <span class="n">K</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>要转换为键函数,只需包装旧的比较函数:</p>
|
||||
<div class="highlight-pycon3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">sorted</span><span class="p">([</span><span class="mi">5</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="n">key</span><span class="o">=</span><span class="n">cmp_to_key</span><span class="p">(</span><span class="n">reverse_numeric</span><span class="p">))</span>
|
||||
<span class="go">[5, 4, 3, 2, 1]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>在 Python 3.2 中, <a class="reference internal" href="../library/functools.html#functools.cmp_to_key" title="functools.cmp_to_key"><code class="xref py py-func docutils literal notranslate"><span class="pre">functools.cmp_to_key()</span></code></a> 函数被添加到标准库中的 <a class="reference internal" href="../library/functools.html#module-functools" title="functools: Higher-order functions and operations on callable objects."><code class="xref py py-mod docutils literal notranslate"><span class="pre">functools</span></code></a> 模块中。</p>
|
||||
</section>
|
||||
<section id="odd-and-ends">
|
||||
<h2>其它<a class="headerlink" href="#odd-and-ends" title="永久链接至标题">¶</a></h2>
|
||||
<ul>
|
||||
<li><p>对于区域相关的排序,请使用 <a class="reference internal" href="../library/locale.html#locale.strxfrm" title="locale.strxfrm"><code class="xref py py-func docutils literal notranslate"><span class="pre">locale.strxfrm()</span></code></a> 作为键函数,或者 <a class="reference internal" href="../library/locale.html#locale.strcoll" title="locale.strcoll"><code class="xref py py-func docutils literal notranslate"><span class="pre">locale.strcoll()</span></code></a> 作为比较函数。</p></li>
|
||||
<li><p><em>reverse</em> 参数仍然保持排序稳定性(因此具有相等键的记录保留原始顺序)。 有趣的是,通过使用内置的 <a class="reference internal" href="../library/functions.html#reversed" title="reversed"><code class="xref py py-func docutils literal notranslate"><span class="pre">reversed()</span></code></a> 函数两次,可以在没有参数的情况下模拟该效果:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="p">[(</span><span class="s1">'red'</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="s1">'blue'</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="s1">'red'</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="s1">'blue'</span><span class="p">,</span> <span class="mi">2</span><span class="p">)]</span>
|
||||
<span class="gp">>>> </span><span class="n">standard_way</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">double_reversed</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="n">key</span><span class="o">=</span><span class="n">itemgetter</span><span class="p">(</span><span class="mi">0</span><span class="p">))))</span>
|
||||
<span class="gp">>>> </span><span class="k">assert</span> <span class="n">standard_way</span> <span class="o">==</span> <span class="n">double_reversed</span>
|
||||
<span class="gp">>>> </span><span class="n">standard_way</span>
|
||||
<span class="go">[('red', 1), ('red', 2), ('blue', 1), ('blue', 2)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li><p>在两个对象之间进行比较时,保证排序例程使用 <a class="reference internal" href="../reference/datamodel.html#object.__lt__" title="object.__lt__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__lt__()</span></code></a> 。 因此,通过定义 <a class="reference internal" href="../reference/datamodel.html#object.__lt__" title="object.__lt__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__lt__()</span></code></a> 方法,可以很容易地为类添加标准排序顺序:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">Student</span><span class="o">.</span><span class="fm">__lt__</span> <span class="o">=</span> <span class="k">lambda</span> <span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">age</span> <span class="o"><</span> <span class="n">other</span><span class="o">.</span><span class="n">age</span>
|
||||
<span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">student_objects</span><span class="p">)</span>
|
||||
<span class="go">[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li><p>键函数不需要直接依赖于被排序的对象。键函数还可以访问外部资源。例如,如果学生成绩存储在字典中,则可以使用它们对单独的学生姓名列表进行排序:</p>
|
||||
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">students</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'dave'</span><span class="p">,</span> <span class="s1">'john'</span><span class="p">,</span> <span class="s1">'jane'</span><span class="p">]</span>
|
||||
<span class="gp">>>> </span><span class="n">newgrades</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'john'</span><span class="p">:</span> <span class="s1">'F'</span><span class="p">,</span> <span class="s1">'jane'</span><span class="p">:</span><span class="s1">'A'</span><span class="p">,</span> <span class="s1">'dave'</span><span class="p">:</span> <span class="s1">'C'</span><span class="p">}</span>
|
||||
<span class="gp">>>> </span><span class="nb">sorted</span><span class="p">(</span><span class="n">students</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">newgrades</span><span class="o">.</span><span class="fm">__getitem__</span><span class="p">)</span>
|
||||
<span class="go">['jane', 'dave', 'john']</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</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="#">排序指南</a><ul>
|
||||
<li><a class="reference internal" href="#sorting-basics">排序的基础知识</a></li>
|
||||
<li><a class="reference internal" href="#key-functions">键函数</a></li>
|
||||
<li><a class="reference internal" href="#operator-module-functions">Operator 模块函数</a></li>
|
||||
<li><a class="reference internal" href="#ascending-and-descending">升序与降序</a></li>
|
||||
<li><a class="reference internal" href="#sort-stability-and-complex-sorts">排序稳定性与复杂排序</a></li>
|
||||
<li><a class="reference internal" href="#the-old-way-using-decorate-sort-undecorate">使用装饰-排序-去装饰的旧方法</a></li>
|
||||
<li><a class="reference internal" href="#the-old-way-using-the-cmp-parameter">使用 <em>cmp</em> 参数的旧方法</a></li>
|
||||
<li><a class="reference internal" href="#odd-and-ends">其它</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="sockets.html"
|
||||
title="上一章">套接字编程指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="unicode.html"
|
||||
title="下一章">Unicode 指南</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/howto/sorting.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="unicode.html" title="Unicode 指南"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="sockets.html" title="套接字编程指南"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
708
web/python-docs/howto/unicode.html
Normal file
708
web/python-docs/howto/unicode.html
Normal file
@@ -0,0 +1,708 @@
|
||||
|
||||
<!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>Unicode 指南 — 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="如何利用 urllib 包获取网络资源" href="urllib2.html" />
|
||||
<link rel="prev" title="排序指南" href="sorting.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/unicode.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="#">Unicode 指南</a><ul>
|
||||
<li><a class="reference internal" href="#introduction-to-unicode">Unicode 概述</a><ul>
|
||||
<li><a class="reference internal" href="#definitions">定义</a></li>
|
||||
<li><a class="reference internal" href="#encodings">编码</a></li>
|
||||
<li><a class="reference internal" href="#references">参考文献</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#python-s-unicode-support">Python对Unicode的支持</a><ul>
|
||||
<li><a class="reference internal" href="#the-string-type">字符串类型</a></li>
|
||||
<li><a class="reference internal" href="#converting-to-bytes">转换为字节</a></li>
|
||||
<li><a class="reference internal" href="#unicode-literals-in-python-source-code">Python 源代码中的 Unicode 文字</a></li>
|
||||
<li><a class="reference internal" href="#unicode-properties">Unicode属性</a></li>
|
||||
<li><a class="reference internal" href="#comparing-strings">字符串比较</a></li>
|
||||
<li><a class="reference internal" href="#unicode-regular-expressions">Unicode 正则表达式</a></li>
|
||||
<li><a class="reference internal" href="#id2">参考文献</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#reading-and-writing-unicode-data">Unicode 数据的读写</a><ul>
|
||||
<li><a class="reference internal" href="#unicode-filenames">Unicode 文件名</a></li>
|
||||
<li><a class="reference internal" href="#tips-for-writing-unicode-aware-programs">识别 Unicode 的编程技巧</a><ul>
|
||||
<li><a class="reference internal" href="#converting-between-file-encodings">在文件编码格式之间进行转换</a></li>
|
||||
<li><a class="reference internal" href="#files-in-an-unknown-encoding">编码格式未知的文件</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#id3">参考文献</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#acknowledgements">致谢</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="sorting.html"
|
||||
title="上一章">排序指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="urllib2.html"
|
||||
title="下一章">如何利用 urllib 包获取网络资源</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/howto/unicode.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/howto/unicode.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="urllib2.html" title="如何利用 urllib 包获取网络资源"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="sorting.html" title="排序指南"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="unicode-howto">
|
||||
<span id="id1"></span><h1>Unicode 指南<a class="headerlink" href="#unicode-howto" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">发布版本</dt>
|
||||
<dd class="field-odd"><p>1.12</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>本文介绍了 Python 对表示文本数据的 Unicode 规范的支持,并对各种 Unicode 常见使用问题做了解释。</p>
|
||||
<section id="introduction-to-unicode">
|
||||
<h2>Unicode 概述<a class="headerlink" href="#introduction-to-unicode" title="永久链接至标题">¶</a></h2>
|
||||
<section id="definitions">
|
||||
<h3>定义<a class="headerlink" href="#definitions" title="永久链接至标题">¶</a></h3>
|
||||
<p>如今的程序需要能够处理各种各样的字符。应用程序通常做了国际化处理,用户可以选择不同的语言显示信息和输出数据。同一个程序可能需要以英语、法语、日语、希伯来语或俄语输出错误信息。网页内容可能由这些语言书写,并且可能包含不同的表情符号。Python 的字符串类型采用 Unicode 标准来表示字符,使得 Python 程序能够正常处理所有这些不同的字符。</p>
|
||||
<p>Unicode 规范(<a class="reference external" href="https://www.unicode.org/">https://www.unicode.org/</a>)旨在罗列人类语言所用到的所有字符,并赋予每个字符唯一的编码。该规范一直在进行修订和更新,不断加入新的语种和符号。</p>
|
||||
<p>一个 <strong>字符</strong> 是文本的最小组件。‘A’、‘B’、‘C’ 等都是不同的字符。‘È’ 和 ‘Í’ 也一样。字符会随着语言或者上下文的变化而变化。比如,‘Ⅰ’ 是一个表示 “罗马数字 1” 的字符,它与大写字母 ‘I’ 不同。他们往往看起来相同,但这是两个有着不同含义的字符。</p>
|
||||
<p>Unicode 标准描述了**码位**如何表示字符。一个码位的值是在 0 到 0x10FFFF (大约 110 万个值,目前有其中 11 万个被指派)。在这一标准中并且在这一文档中,一个码位写作 <code class="docutils literal notranslate"><span class="pre">U+265E</span></code> 来表示拥有值 <code class="docutils literal notranslate"><span class="pre">0x265e</span></code> 的字符(十进制下为 9,822)。</p>
|
||||
<p>Unicode 标准中包含了许多表格,列出了很多字符及其对应的码位。</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>0061 'a'; LATIN SMALL LETTER A
|
||||
0062 'b'; LATIN SMALL LETTER B
|
||||
0063 'c'; LATIN SMALL LETTER C
|
||||
...
|
||||
007B '{'; LEFT CURLY BRACKET
|
||||
...
|
||||
2167 'Ⅷ'; ROMAN NUMERAL EIGHT
|
||||
2168 'Ⅸ'; ROMAN NUMERAL NINE
|
||||
...
|
||||
265E '♞'; BLACK CHESS KNIGHT
|
||||
265F '♟'; BLACK CHESS PAWN
|
||||
...
|
||||
1F600 '😀'; GRINNING FACE
|
||||
1F609 '😉'; WINKING FACE
|
||||
...
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>严格地说,上述定义暗示了以下说法是没有意义的:“这是字符 <code class="docutils literal notranslate"><span class="pre">U+265E</span></code>”。<code class="docutils literal notranslate"><span class="pre">U+265E</span></code> 只是一个码位,代表某个特定的字符;这里它代表了字符 “国际象棋黑骑士” '♞'。在非正式的上下文中,有时会忽略码位和字符的区别。</p>
|
||||
<p>一个字符在屏幕或纸上被表示为一组图形元素,被称为 <strong>字形(glyph)</strong> 。比如,大写字母 A 的字形,是两笔斜线和一笔横线,而具体的细节取决于所使用的字体。大部分 Python 代码不必担心字形,找到正确的显示字形通常是交给 GUI 工具包或终端的字体渲染程序来完成。</p>
|
||||
</section>
|
||||
<section id="encodings">
|
||||
<h3>编码<a class="headerlink" href="#encodings" title="永久链接至标题">¶</a></h3>
|
||||
<p>上一段可以归结为:一个 Unicode 字符串是一系列码位(从 0 到 <code class="docutils literal notranslate"><span class="pre">0x10FFFF</span></code> 或者说十进制的 1,114,111 的数字)组成的序列。这一序列在内存中需被表示为一组 <strong>码元(code unit)</strong> , <strong>码元</strong> 会映射成包含八个二进制位的字节。将 Unicode 字符串翻译成字节序列的规则称为 <strong>字符编码</strong> ,或者 <strong>编码</strong> 。</p>
|
||||
<p>大家首先会想到的编码可能是用 32 位的整数作为代码位,然后采用 CPU 对 32 位整数的表示法。字符串 “Python” 用这种表示法可能会如下所示:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> P y t h o n
|
||||
0x50 00 00 00 79 00 00 00 74 00 00 00 68 00 00 00 6f 00 00 00 6e 00 00 00
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这种表示法非常直白,但也存在 一些问题。</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>不具可移植性;不同的处理器的字节序不同。</p></li>
|
||||
<li><p>非常浪费空间。 在大多数文本中,大部分码位都小于 127 或 255,因此字节 <code class="docutils literal notranslate"><span class="pre">0x00</span></code> 占用了大量空间。相较于 ASCII 表示法所需的 6 个字节,以上字符串需要占用 24 个字节。RAM 用量的增加没那么要紧(台式计算机有成 GB 的 RAM,而字符串通常不会有那么大),但要把磁盘和网络带宽的用量增加 4 倍是无法忍受的。</p></li>
|
||||
<li><p>与现有的 C 函数(如 <code class="docutils literal notranslate"><span class="pre">strlen()</span></code> )不兼容,因此需要采用一套新的宽字符串函数。</p></li>
|
||||
</ol>
|
||||
<p>因此这种编码用得不多,人们转而选择其他更高效、更方便的编码,比如 UTF-8。</p>
|
||||
<p>UTF-8 是最常用的编码之一,Python 往往默认会采用它。UTF 代表“Unicode Transformation Format”,'8' 表示编码采用 8 位数。(UTF-16 和 UTF-32 编码也是存在的,但其使用频率不如 UTF-8。)UTF-8 的规则如下:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>如果码位 < 128,则直接用对应的字节值表示。</p></li>
|
||||
<li><p>如果码位 >= 128,则转换为 2、3、4 个字节的序列,每个字节值都位于 128 和 255 之间。</p></li>
|
||||
</ol>
|
||||
<p>UTF-8 有几个很方便的特性:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>可以处理任何 Unicode 码位。</p></li>
|
||||
<li><p>Unicode 字符串被转换为一个字节序列,仅在表示空(null )字符(U+0000)时才会包含零值的字节。这意味着 <code class="docutils literal notranslate"><span class="pre">strcpy()</span></code> 之类的C 函数可以处理 UTF-8 字符串,而且用那些不能处理字符串结束符之外的零值字节的协议也能发送。</p></li>
|
||||
<li><p>ASCII 字符串也是也是也是合法的 UTF-8 文本。</p></li>
|
||||
<li><p>UTF-8 相当紧凑;大多数常用字符均可用一两个字节表示。</p></li>
|
||||
<li><p>如果字节数据被损坏或丢失,则可以找出下一个 UTF-8 码点的开始位置并重新开始同步。随机的 8 位数据也不太可能像是有效的 UTF-8 编码。</p></li>
|
||||
<li><p>UTF-8 是一种面向字节的编码。编码规定了每个字符由一个或多个字节的序列表示。这避免了整数和双字节编码(如 UTF-16 和 UTF-32)可能出现的字节顺序问题,那时的字节序列会因执行编码的硬件而异。</p></li>
|
||||
</ol>
|
||||
</section>
|
||||
<section id="references">
|
||||
<h3>参考文献<a class="headerlink" href="#references" title="永久链接至标题">¶</a></h3>
|
||||
<p><a class="reference external" href="http://www.unicode.org">Unicode Consortium 站点</a> 有 Unicode 规范的字符图表、词汇表和 PDF 版本。 为一些困难的阅读做好准备。 <a class="reference external" href="http://www.unicode.org/history/">Unicode 起源和发展的年表</a> 也可在该站点上找到。</p>
|
||||
<p>在 Computerphile 的 Youtube 频道上,Tom Scott 简要地 <a class="reference external" href="https://www.youtube.com/watch?v=MijmeoH9LT4">讨论了 Unicode 和 UTF-8</a> (9 分 36 秒)的历史。</p>
|
||||
<p>为了帮助理解该标准,Jukka Korpela 编写了阅读 Unicode 字符表的`介绍性指南 <<a class="reference external" href="http://jkorpela.fi/unicode/guide.html">http://jkorpela.fi/unicode/guide.html</a>>`_ 。</p>
|
||||
<p>Joel Spolsky 撰写了另一篇不错的介绍性文章 <<a class="reference external" href="https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character">https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character</a>- set-no-excuses/>`_ 。如果本文没让您弄清楚,那应在继续之前先试着读读这篇文章。</p>
|
||||
<p>Wikipedia 条目通常也有帮助;请参阅“<a class="reference external" href="https://en.wikipedia.org/wiki/Character_encoding">字符编码</a>”和 <a class="reference external" href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> 的条目,例如:</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="python-s-unicode-support">
|
||||
<h2>Python对Unicode的支持<a class="headerlink" href="#python-s-unicode-support" title="永久链接至标题">¶</a></h2>
|
||||
<p>现在您已经了解了 Unicode 的基础知识,可以看下 Python 的 Unicode 特性。</p>
|
||||
<section id="the-string-type">
|
||||
<h3>字符串类型<a class="headerlink" href="#the-string-type" title="永久链接至标题">¶</a></h3>
|
||||
<p>从 Python 3.0 开始, <a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a> 类型包含了 Unicode 字符,这意味着用 <code class="docutils literal notranslate"><span class="pre">"unicode</span> <span class="pre">rocks!"</span></code>、<code class="docutils literal notranslate"><span class="pre">'unicode</span> <span class="pre">rocks!'</span></code> 或三重引号字符串语法创建的任何字符串都会存储为 Unicode。</p>
|
||||
<p>Python 源代码的默认编码是 UTF-8,因此可以直接在字符串中包含 Unicode 字符:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'/tmp/input.txt'</span><span class="p">,</span> <span class="s1">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="o">...</span>
|
||||
<span class="k">except</span> <span class="ne">OSError</span><span class="p">:</span>
|
||||
<span class="c1"># 'File not found' error message.</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Fichier non trouvé"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>旁注:Python 3 还支持在标识符中使用 Unicode 字符:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">répertoire</span> <span class="o">=</span> <span class="s2">"/tmp/records.log"</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">répertoire</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"test</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如果无法在编辑器中输入某个字符,或出于某种原因想只保留 ASCII 编码的源代码,则还可以在字符串中使用转义序列。(根据系统的不同,可能会看到真的大写 Delta 字体而不是 u 转义符。):</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="s2">"</span><span class="se">\N{GREEK CAPITAL LETTER DELTA}</span><span class="s2">"</span> <span class="c1"># Using the character name</span>
|
||||
<span class="go">'\u0394'</span>
|
||||
<span class="gp">>>> </span><span class="s2">"</span><span class="se">\u0394</span><span class="s2">"</span> <span class="c1"># Using a 16-bit hex value</span>
|
||||
<span class="go">'\u0394'</span>
|
||||
<span class="gp">>>> </span><span class="s2">"</span><span class="se">\U00000394</span><span class="s2">"</span> <span class="c1"># Using a 32-bit hex value</span>
|
||||
<span class="go">'\u0394'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>此外,可以用 <a class="reference internal" href="../library/stdtypes.html#bytes" title="bytes"><code class="xref py py-class docutils literal notranslate"><span class="pre">bytes</span></code></a> 的 <a class="reference internal" href="../library/stdtypes.html#bytes.decode" title="bytes.decode"><code class="xref py py-func docutils literal notranslate"><span class="pre">decode()</span></code></a> 方法创建一个字符串。 该方法可以接受 <em>encoding</em> 参数,比如可以为 <code class="docutils literal notranslate"><span class="pre">UTF-8</span></code> ,以及可选的 <em>errors</em> 参数。</p>
|
||||
<p>若无法根据编码规则对输入字符串进行编码,<em>errors</em> 参数指定了响应策略。 该参数的合法值可以是 <code class="docutils literal notranslate"><span class="pre">'strict'</span></code> (触发 <a class="reference internal" href="../library/exceptions.html#UnicodeDecodeError" title="UnicodeDecodeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">UnicodeDecodeError</span></code></a> 异常)、<code class="docutils literal notranslate"><span class="pre">'replace'</span></code> (用 <code class="docutils literal notranslate"><span class="pre">U+FFFD</span></code>、<code class="docutils literal notranslate"><span class="pre">REPLACEMENT</span> <span class="pre">CHARACTER</span></code>)、<code class="docutils literal notranslate"><span class="pre">'ignore'</span></code> (只是将字符从 Unicode 结果中去掉),或 <code class="docutils literal notranslate"><span class="pre">'backslashreplace'</span></code> (插入一个 <code class="docutils literal notranslate"><span class="pre">\xNN</span></code> 转义序列)。 以下示例演示了这些不同的参数:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="sa">b</span><span class="s1">'</span><span class="se">\x80</span><span class="s1">abc'</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">,</span> <span class="s2">"strict"</span><span class="p">)</span>
|
||||
<span class="gt">Traceback (most recent call last):</span>
|
||||
<span class="w"> </span><span class="o">...</span>
|
||||
<span class="gr">UnicodeDecodeError</span>: <span class="n">'utf-8' codec can't decode byte 0x80 in position 0:</span>
|
||||
<span class="x"> invalid start byte</span>
|
||||
<span class="gp">>>> </span><span class="sa">b</span><span class="s1">'</span><span class="se">\x80</span><span class="s1">abc'</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">,</span> <span class="s2">"replace"</span><span class="p">)</span>
|
||||
<span class="go">'\ufffdabc'</span>
|
||||
<span class="gp">>>> </span><span class="sa">b</span><span class="s1">'</span><span class="se">\x80</span><span class="s1">abc'</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">,</span> <span class="s2">"backslashreplace"</span><span class="p">)</span>
|
||||
<span class="go">'\\x80abc'</span>
|
||||
<span class="gp">>>> </span><span class="sa">b</span><span class="s1">'</span><span class="se">\x80</span><span class="s1">abc'</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">,</span> <span class="s2">"ignore"</span><span class="p">)</span>
|
||||
<span class="go">'abc'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>编码格式以包含编码格式名称的字符串来指明。 Python 有大约 100 种不同的编码格式;清单详见 Python 库参考文档 <a class="reference internal" href="../library/codecs.html#standard-encodings"><span class="std std-ref">标准编码</span></a>。 一些编码格式有多个名称,比如 <code class="docutils literal notranslate"><span class="pre">'latin-1'</span></code>、<code class="docutils literal notranslate"><span class="pre">'iso_8859_1'</span></code> 和 <code class="docutils literal notranslate"><span class="pre">'8859</span></code> 都是指同一种编码。</p>
|
||||
<p>利用内置函数 <a class="reference internal" href="../library/functions.html#chr" title="chr"><code class="xref py py-func docutils literal notranslate"><span class="pre">chr()</span></code></a> 还可以创建单字符的 Unicode 字符串,该函数可接受整数参数,并返回包含对应码位的长度为 1 的 Unicode 字符串。内置函数 <a class="reference internal" href="../library/functions.html#ord" title="ord"><code class="xref py py-func docutils literal notranslate"><span class="pre">ord()</span></code></a> 是其逆操作,参数为单个字符的 Unicode 字符串,并返回码位值:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">chr</span><span class="p">(</span><span class="mi">57344</span><span class="p">)</span>
|
||||
<span class="go">'\ue000'</span>
|
||||
<span class="gp">>>> </span><span class="nb">ord</span><span class="p">(</span><span class="s1">'</span><span class="se">\ue000</span><span class="s1">'</span><span class="p">)</span>
|
||||
<span class="go">57344</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="converting-to-bytes">
|
||||
<h3>转换为字节<a class="headerlink" href="#converting-to-bytes" title="永久链接至标题">¶</a></h3>
|
||||
<p><a class="reference internal" href="../library/stdtypes.html#bytes.decode" title="bytes.decode"><code class="xref py py-meth docutils literal notranslate"><span class="pre">bytes.decode()</span></code></a> 的逆方法是 <a class="reference internal" href="../library/stdtypes.html#str.encode" title="str.encode"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.encode()</span></code></a> ,它会返回 Unicode 字符串的 <a class="reference internal" href="../library/stdtypes.html#bytes" title="bytes"><code class="xref py py-class docutils literal notranslate"><span class="pre">bytes</span></code></a> 形式,已按要求的 <em>encoding</em> 进行了编码。</p>
|
||||
<p>参数 <em>errors</em> 的意义与 <a class="reference internal" href="../library/stdtypes.html#bytes.decode" title="bytes.decode"><code class="xref py py-meth docutils literal notranslate"><span class="pre">decode()</span></code></a> 方法相同,但支持更多可能的handler。除了 <code class="docutils literal notranslate"><span class="pre">'strict'</span></code> 、 <code class="docutils literal notranslate"><span class="pre">'ignore'</span></code> 和 <code class="docutils literal notranslate"><span class="pre">'replace'</span></code> (这时会插入问号替换掉无法编码的字符),还有 <code class="docutils literal notranslate"><span class="pre">'xmlcharrefreplace'</span></code> (插入一个 XML 字符引用)、 <code class="docutils literal notranslate"><span class="pre">backslashreplace</span></code> (插入一个 <code class="docutils literal notranslate"><span class="pre">\uNNNN</span></code> 转义序列)和 <code class="docutils literal notranslate"><span class="pre">namereplace</span></code> (插入一个 <code class="docutils literal notranslate"><span class="pre">\N{...}</span></code> 转义序列 )。</p>
|
||||
<p>以下例子演示了各种不同的结果:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">u</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">40960</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'abcd'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">1972</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'utf-8'</span><span class="p">)</span>
|
||||
<span class="go">b'\xea\x80\x80abcd\xde\xb4'</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">)</span>
|
||||
<span class="gt">Traceback (most recent call last):</span>
|
||||
<span class="w"> </span><span class="o">...</span>
|
||||
<span class="gr">UnicodeEncodeError</span>: <span class="n">'ascii' codec can't encode character '\ua000' in</span>
|
||||
<span class="x"> position 0: ordinal not in range(128)</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">,</span> <span class="s1">'ignore'</span><span class="p">)</span>
|
||||
<span class="go">b'abcd'</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">,</span> <span class="s1">'replace'</span><span class="p">)</span>
|
||||
<span class="go">b'?abcd?'</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">,</span> <span class="s1">'xmlcharrefreplace'</span><span class="p">)</span>
|
||||
<span class="go">b'&#40960;abcd&#1972;'</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">,</span> <span class="s1">'backslashreplace'</span><span class="p">)</span>
|
||||
<span class="go">b'\\ua000abcd\\u07b4'</span>
|
||||
<span class="gp">>>> </span><span class="n">u</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">,</span> <span class="s1">'namereplace'</span><span class="p">)</span>
|
||||
<span class="go">b'\\N{YI SYLLABLE IT}abcd\\u07b4'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>用于注册和访问可用编码格式的底层函数,位于 <a class="reference internal" href="../library/codecs.html#module-codecs" title="codecs: Encode and decode data and streams."><code class="xref py py-mod docutils literal notranslate"><span class="pre">codecs</span></code></a> 模块中。 若要实现新的编码格式,则还需要了解 <a class="reference internal" href="../library/codecs.html#module-codecs" title="codecs: Encode and decode data and streams."><code class="xref py py-mod docutils literal notranslate"><span class="pre">codecs</span></code></a> 模块。 不过该模块返回的编码和解码函数通常更为底层一些,不大好用,编写新的编码格式是一项专业的任务,因此本文不会涉及该模块。</p>
|
||||
</section>
|
||||
<section id="unicode-literals-in-python-source-code">
|
||||
<h3>Python 源代码中的 Unicode 文字<a class="headerlink" href="#unicode-literals-in-python-source-code" title="永久链接至标题">¶</a></h3>
|
||||
<p>在 Python 源代码中,可以用 <code class="docutils literal notranslate"><span class="pre">\u</span></code> 转义序列书写特定的 Unicode 码位,该序列后跟 4 个代表码位的十六进制数字。<code class="docutils literal notranslate"><span class="pre">\U</span></code> 转义序列用法类似,但要用8 个十六进制数字,而不是 4 个:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">s</span> <span class="o">=</span> <span class="s2">"a</span><span class="se">\xac\u1234\u20ac\U00008000</span><span class="s2">"</span>
|
||||
<span class="gp">... </span><span class="c1"># ^^^^ two-digit hex escape</span>
|
||||
<span class="gp">... </span><span class="c1"># ^^^^^^ four-digit Unicode escape</span>
|
||||
<span class="gp">... </span><span class="c1"># ^^^^^^^^^^ eight-digit Unicode escape</span>
|
||||
<span class="gp">>>> </span><span class="p">[</span><span class="nb">ord</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">s</span><span class="p">]</span>
|
||||
<span class="go">[97, 172, 4660, 8364, 32768]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>对大于 127 的码位使用转义序列,数量不多时没什么问题,但如果要用到很多重音字符,这会变得很烦人,类似于程序中的信息是用法语或其他使用重音的语言写的。也可以用内置函数 <a class="reference internal" href="../library/functions.html#chr" title="chr"><code class="xref py py-func docutils literal notranslate"><span class="pre">chr()</span></code></a> 拼装字符串,但会更加乏味。</p>
|
||||
<p>理想情况下,都希望能用母语的编码书写文本。还能用喜好的编辑器编辑 Python 源代码,编辑器要能自然地显示重音符,并在运行时使用正确的字符。</p>
|
||||
<p>默认情况下,Python 支持以 UTF-8 格式编写源代码,但如果声明要用的编码,则几乎可以使用任何编码。只要在源文件的第一行或第二行包含一个特殊注释即可:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env python</span>
|
||||
<span class="c1"># -*- coding: latin-1 -*-</span>
|
||||
|
||||
<span class="n">u</span> <span class="o">=</span> <span class="s1">'abcdé'</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="nb">ord</span><span class="p">(</span><span class="n">u</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>上述语法的灵感来自于 Emacs 用于指定文件局部变量的符号。Emacs 支持许多不同的变量,但 Python 仅支持“编码”。 <code class="docutils literal notranslate"><span class="pre">-*-</span></code> 符号向 Emacs 标明该注释是特殊的;这对 Python 没有什么意义,只是一种约定。Python 会在注释中查找 <code class="docutils literal notranslate"><span class="pre">coding:</span> <span class="pre">name</span></code> 或 <code class="docutils literal notranslate"><span class="pre">coding=name</span></code> 。</p>
|
||||
<p>如果没有这种注释,则默认编码将会是前面提到的 UTF-8。更多信息请参阅 <span class="target" id="index-2"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0263"><strong>PEP 263</strong></a> 。</p>
|
||||
</section>
|
||||
<section id="unicode-properties">
|
||||
<h3>Unicode属性<a class="headerlink" href="#unicode-properties" title="永久链接至标题">¶</a></h3>
|
||||
<p>Unicode 规范包含了一个码位信息数据库。对于定义的每一个码位,都包含了字符的名称、类别、数值(对于表示数字概念的字符,如罗马数字、分数如三分之一和五分之四等)。还有有关显示的属性,比如如何在双向文本中使用码位。</p>
|
||||
<p>以下程序显示了几个字符的信息,并打印一个字符的数值:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">unicodedata</span>
|
||||
|
||||
<span class="n">u</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">233</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="mh">0x0bf2</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">3972</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">6000</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">13231</span><span class="p">)</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">u</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="s1">'</span><span class="si">%04x</span><span class="s1">'</span> <span class="o">%</span> <span class="nb">ord</span><span class="p">(</span><span class="n">c</span><span class="p">),</span> <span class="n">unicodedata</span><span class="o">.</span><span class="n">category</span><span class="p">(</span><span class="n">c</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">unicodedata</span><span class="o">.</span><span class="n">name</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
|
||||
|
||||
<span class="c1"># Get numeric value of second character</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">unicodedata</span><span class="o">.</span><span class="n">numeric</span><span class="p">(</span><span class="n">u</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>当运行时,这将打印出:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>0 00e9 Ll LATIN SMALL LETTER E WITH ACUTE
|
||||
1 0bf2 No TAMIL NUMBER ONE THOUSAND
|
||||
2 0f84 Mn TIBETAN MARK HALANTA
|
||||
3 1770 Lo TAGBANWA LETTER SA
|
||||
4 33af So SQUARE RAD OVER S SQUARED
|
||||
1000.0
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>类别代码是描述字符性质的缩写。 这些被分组为“字母”、“数字”、“标点符号”或“符号”等类别,而这些类别又分为子类别。 从上面的输出中获取代码,<code class="docutils literal notranslate"><span class="pre">'Ll'</span></code> 表示“字母,小写”,<code class="docutils literal notranslate"><span class="pre">'No'</span></code> 表示“数字,其他”,<code class="docutils literal notranslate"><span class="pre">'Mn'</span></code> 是“标记,非间距”,<code class="docutils literal notranslate"><span class="pre">'So'</span></code> 是“符号,其他”。 有关类别代码列表,请参阅 Unicode 字符数据库文档 <<a class="reference external" href="http://www.unicode.org/reports/tr44/#General_Category_Values">http://www.unicode.org/reports/tr44/#General_Category_Values</a>>`_ 的“通用类别值”部分。</p>
|
||||
</section>
|
||||
<section id="comparing-strings">
|
||||
<h3>字符串比较<a class="headerlink" href="#comparing-strings" title="永久链接至标题">¶</a></h3>
|
||||
<p>Unicode 让字符串的比较变得复杂了一些,因为同一组字符可能由不同的码位序列组成。例如,像“ê”这样的字母可以表示为单码位 U+00EA,或是 U+0065 U+0302,即“e”的码位后跟“COMBINING CIRCUMFLEX ACCENT”的码位。虽然在打印时会产生同样的输出,但一个是长度为 1 的字符串,另一个是长度为 2 的字符串。</p>
|
||||
<p>一种不区分大小写比较的工具是字符串方法 <a class="reference internal" href="../library/stdtypes.html#str.casefold" title="str.casefold"><code class="xref py py-meth docutils literal notranslate"><span class="pre">casefold()</span></code></a> ,将按照 Unicode 标准描述的算法将字符串转换为不区分大小写的形式。该算法对诸如德语字母“ß”(代码点 U+00DF)之类的字符进行了特殊处理,变为一对小写字母“ss”。</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">street</span> <span class="o">=</span> <span class="s1">'Gürzenichstraße'</span>
|
||||
<span class="gp">>>> </span><span class="n">street</span><span class="o">.</span><span class="n">casefold</span><span class="p">()</span>
|
||||
<span class="go">'gürzenichstrasse'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>第二个工具是 <a class="reference internal" href="../library/unicodedata.html#module-unicodedata" title="unicodedata: Access the Unicode Database."><code class="xref py py-mod docutils literal notranslate"><span class="pre">unicodedata</span></code></a> 模块的 <a class="reference internal" href="../library/unicodedata.html#unicodedata.normalize" title="unicodedata.normalize"><code class="xref py py-func docutils literal notranslate"><span class="pre">normalize()</span></code></a> 函数,将字符串转换为几种规范化形式之一,其中后跟组合字符的字母将被替换为单个字符。 <code class="xref py py-func docutils literal notranslate"><span class="pre">normalize()</span></code> 可用于执行字符串比较,即便两个字符串采用不同的字符组合,也不会错误地报告两者不相等:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">unicodedata</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">compare_strs</span><span class="p">(</span><span class="n">s1</span><span class="p">,</span> <span class="n">s2</span><span class="p">):</span>
|
||||
<span class="k">def</span> <span class="nf">NFD</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">unicodedata</span><span class="o">.</span><span class="n">normalize</span><span class="p">(</span><span class="s1">'NFD'</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">NFD</span><span class="p">(</span><span class="n">s1</span><span class="p">)</span> <span class="o">==</span> <span class="n">NFD</span><span class="p">(</span><span class="n">s2</span><span class="p">)</span>
|
||||
|
||||
<span class="n">single_char</span> <span class="o">=</span> <span class="s1">'ê'</span>
|
||||
<span class="n">multiple_chars</span> <span class="o">=</span> <span class="s1">'</span><span class="se">\N{LATIN SMALL LETTER E}\N{COMBINING CIRCUMFLEX ACCENT}</span><span class="s1">'</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'length of first string='</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">single_char</span><span class="p">))</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'length of second string='</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">multiple_chars</span><span class="p">))</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">compare_strs</span><span class="p">(</span><span class="n">single_char</span><span class="p">,</span> <span class="n">multiple_chars</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>当运行时,这将输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python3<span class="w"> </span>compare-strs.py
|
||||
<span class="go">length of first string= 1</span>
|
||||
<span class="go">length of second string= 2</span>
|
||||
<span class="go">True</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><a class="reference internal" href="../library/unicodedata.html#unicodedata.normalize" title="unicodedata.normalize"><code class="xref py py-func docutils literal notranslate"><span class="pre">normalize()</span></code></a> 函数的第一个参数是个字符串,给出所需的规范化形式,可以是“NFC”、“NFKC”、“NFD”和“NFKD”之一。</p>
|
||||
<p>Unicode 标准还设定了如何进行不区分大小写的比较:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">unicodedata</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">compare_caseless</span><span class="p">(</span><span class="n">s1</span><span class="p">,</span> <span class="n">s2</span><span class="p">):</span>
|
||||
<span class="k">def</span> <span class="nf">NFD</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">unicodedata</span><span class="o">.</span><span class="n">normalize</span><span class="p">(</span><span class="s1">'NFD'</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">NFD</span><span class="p">(</span><span class="n">NFD</span><span class="p">(</span><span class="n">s1</span><span class="p">)</span><span class="o">.</span><span class="n">casefold</span><span class="p">())</span> <span class="o">==</span> <span class="n">NFD</span><span class="p">(</span><span class="n">NFD</span><span class="p">(</span><span class="n">s2</span><span class="p">)</span><span class="o">.</span><span class="n">casefold</span><span class="p">())</span>
|
||||
|
||||
<span class="c1"># Example usage</span>
|
||||
<span class="n">single_char</span> <span class="o">=</span> <span class="s1">'ê'</span>
|
||||
<span class="n">multiple_chars</span> <span class="o">=</span> <span class="s1">'</span><span class="se">\N{LATIN CAPITAL LETTER E}\N{COMBINING CIRCUMFLEX ACCENT}</span><span class="s1">'</span>
|
||||
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">compare_caseless</span><span class="p">(</span><span class="n">single_char</span><span class="p">,</span> <span class="n">multiple_chars</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>这将打印 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。(为什么 <code class="xref py py-func docutils literal notranslate"><span class="pre">NFD()</span></code> 会被调用两次?因为有几个字符让 <code class="xref py py-meth docutils literal notranslate"><span class="pre">casefold()</span></code> 返回非规范化的字符串,所以结果需要再次进行规范化。参见 Unicode 标准的 3.13 节 的一个讨论和示例。)</p>
|
||||
</section>
|
||||
<section id="unicode-regular-expressions">
|
||||
<h3>Unicode 正则表达式<a class="headerlink" href="#unicode-regular-expressions" title="永久链接至标题">¶</a></h3>
|
||||
<p><a class="reference internal" href="../library/re.html#module-re" title="re: Regular expression operations."><code class="xref py py-mod docutils literal notranslate"><span class="pre">re</span></code></a> 模块支持的正则表达式可以用字节串或字符串的形式提供。有一些特殊字符序列,比如 <code class="docutils literal notranslate"><span class="pre">\d</span></code> 和 <code class="docutils literal notranslate"><span class="pre">\w</span></code> 具有不同的含义,具体取决于匹配模式是以字节串还是字符串形式提供的。例如,<code class="docutils literal notranslate"><span class="pre">\d</span></code> 将匹配字节串中的字符 <code class="docutils literal notranslate"><span class="pre">[0-9]</span></code> ,但对于字符串将会匹配 <code class="docutils literal notranslate"><span class="pre">'Nd'</span></code> 类别中的任何字符。</p>
|
||||
<p>上述示例中的字符串包含了泰语和阿拉伯数字书写的数字 57:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">re</span>
|
||||
<span class="n">p</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">'\d+'</span><span class="p">)</span>
|
||||
|
||||
<span class="n">s</span> <span class="o">=</span> <span class="s2">"Over </span><span class="se">\u0e55\u0e57</span><span class="s2"> 57 flavours"</span>
|
||||
<span class="n">m</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">()))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>执行时,<code class="docutils literal notranslate"><span class="pre">\d+</span></code> 将匹配上泰语数字并打印出来。如果向 <a class="reference internal" href="../library/re.html#re.compile" title="re.compile"><code class="xref py py-func docutils literal notranslate"><span class="pre">compile()</span></code></a> 提供的是 <a class="reference internal" href="../library/re.html#re.ASCII" title="re.ASCII"><code class="xref py py-const docutils literal notranslate"><span class="pre">re.ASCII</span></code></a> 标志,<code class="docutils literal notranslate"><span class="pre">\d+</span></code> 则会匹配子串 "57"。</p>
|
||||
<p>类似地,<code class="docutils literal notranslate"><span class="pre">\w</span></code> 将匹配多种 Unicode 字符,但对于字节串则只会匹配 <code class="docutils literal notranslate"><span class="pre">[a-zA-Z0-9_]</span></code> ,如果指定 <a class="reference internal" href="../library/re.html#re.ASCII" title="re.ASCII"><code class="xref py py-const docutils literal notranslate"><span class="pre">re.ASCII</span></code></a> , <code class="docutils literal notranslate"><span class="pre">\s</span></code> 将匹配 Unicode 空白符或 <code class="docutils literal notranslate"><span class="pre">[</span> <span class="pre">\t\n\r\f\v]</span></code> 。</p>
|
||||
</section>
|
||||
<section id="id2">
|
||||
<h3>参考文献<a class="headerlink" href="#id2" title="永久链接至标题">¶</a></h3>
|
||||
<p>关于 Python 的 Unicode 支持,其他还有一些很好的讨论:</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference external" href="http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html">用 Python 3 处理文本文件</a> ,作者 Nick Coghlan。</p></li>
|
||||
<li><p><a class="reference external" href="https://nedbatchelder.com/text/unipain.html">实用的 Unicode</a>,Ned Batchelder 在 PyCon 2012 上的演示。</p></li>
|
||||
</ul>
|
||||
<p><a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a> 类型在 Python 库参考文档 <a class="reference internal" href="../library/stdtypes.html#textseq"><span class="std std-ref">文本序列类型 --- str</span></a> 中有介绍。</p>
|
||||
<p><a class="reference internal" href="../library/unicodedata.html#module-unicodedata" title="unicodedata: Access the Unicode Database."><code class="xref py py-mod docutils literal notranslate"><span class="pre">unicodedata</span></code></a> 模块的文档</p>
|
||||
<p><a class="reference internal" href="../library/codecs.html#module-codecs" title="codecs: Encode and decode data and streams."><code class="xref py py-mod docutils literal notranslate"><span class="pre">codecs</span></code></a> 模块的文档</p>
|
||||
<p>Marc-André Lemburg 在 EuroPython 2002 上做了一个题为“Python 和 Unicode”(PDF 幻灯片)<<a class="reference external" href="https://downloads.egenix.com/python/Unicode-EPC2002-Talk.pdf">https://downloads.egenix.com/python/Unicode-EPC2002-Talk.pdf</a>>`_ 的演示文稿。该幻灯片很好地概括了 Python 2 的 Unicode 功能设计(其中 Unicode 字符串类型称为 <code class="docutils literal notranslate"><span class="pre">unicode</span></code>,文字以 <code class="docutils literal notranslate"><span class="pre">u</span></code> 开头)。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="reading-and-writing-unicode-data">
|
||||
<h2>Unicode 数据的读写<a class="headerlink" href="#reading-and-writing-unicode-data" title="永久链接至标题">¶</a></h2>
|
||||
<p>既然处理 Unicode 数据的代码写好了,下一个问题就是输入/输出了。如何将 Unicode 字符串读入程序,如何将 Unicode 转换为适于存储或传输的形式呢?</p>
|
||||
<p>根据输入源和输出目标的不同,或许什么都不用干;请检查一下应用程序用到的库是否原生支持 Unicode。例如,XML 解析器往往会返回 Unicode 数据。许多关系数据库的字段也支持 Unicode 值,并且 SQL 查询也能返回 Unicode 值。</p>
|
||||
<p>在写入磁盘或通过套接字发送之前,Unicode 数据通常要转换为特定的编码。可以自己完成所有工作:打开一个文件,从中读取一个 8 位字节对象,然后用 <code class="docutils literal notranslate"><span class="pre">bytes.decode(encoding)</span></code> 对字节串进行转换。但是,不推荐采用这种全人工的方案。</p>
|
||||
<p>编码的多字节特性就是一个难题; 一个 Unicode 字符可以用几个字节表示。 如果要以任意大小的块(例如 1024 或 4096 字节)读取文件,那么在块的末尾可能只读到某个 Unicode 字符的部分字节,这就需要编写错误处理代码。 有一种解决方案是将整个文件读入内存,然后进行解码,但这样就没法处理很大的文件了;若要读取 2 GB 的文件,就需要 2 GB 的 RAM。(其实需要的内存会更多些,因为至少有一段时间需要在内存中同时存放已编码字符串及其 Unicode 版本。)</p>
|
||||
<p>解决方案是利用底层解码接口去捕获编码序列不完整的情况。这部分代码已经是现成的:内置函数 <a class="reference internal" href="../library/functions.html#open" title="open"><code class="xref py py-func docutils literal notranslate"><span class="pre">open()</span></code></a> 可以返回一个文件类的对象,该对象认为文件的内容采用指定的编码,<a class="reference internal" href="../library/io.html#io.TextIOBase.read" title="io.TextIOBase.read"><code class="xref py py-meth docutils literal notranslate"><span class="pre">read()</span></code></a> 和 <a class="reference internal" href="../library/io.html#io.TextIOBase.write" title="io.TextIOBase.write"><code class="xref py py-meth docutils literal notranslate"><span class="pre">write()</span></code></a> 等方法接受 Unicode 参数。只要用 <a class="reference internal" href="../library/functions.html#open" title="open"><code class="xref py py-func docutils literal notranslate"><span class="pre">open()</span></code></a> 的 <em>encoding</em> 和 <em>errors</em> 参数即可,参数释义同 <a class="reference internal" href="../library/stdtypes.html#str.encode" title="str.encode"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.encode()</span></code></a> 和 <a class="reference internal" href="../library/stdtypes.html#bytes.decode" title="bytes.decode"><code class="xref py py-meth docutils literal notranslate"><span class="pre">bytes.decode()</span></code></a> 。</p>
|
||||
<p>因此从文件读取 Unicode 就比较简单了:</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="s1">'unicode.txt'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s1">'utf-8'</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="nb">repr</span><span class="p">(</span><span class="n">line</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>也可以在更新模式下打开文件,以便同时读取和写入:</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="s1">'test'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s1">'utf-8'</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s1">'w+'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'</span><span class="se">\u4500</span><span class="s1"> blah blah blah</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
|
||||
<span class="n">f</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">readline</span><span class="p">()[:</span><span class="mi">1</span><span class="p">]))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Unicode 字符 <code class="docutils literal notranslate"><span class="pre">U+FEFF</span></code> 用作字节顺序标记(BOM),通常作为文件的第一个字符写入,以帮助自动检测文件的字节顺序。某些编码(例如 UTF-16)期望在文件开头出现 BOM;当采用这种编码时,BOM 将自动作为第一个字符写入,并在读取文件时会静默删除。这些编码有多种变体,例如用于 little-endian 和 big-endian 编码的 “utf-16-le” 和 “utf-16-be”,会指定一种特定的字节顺序并且不会忽略 BOM。</p>
|
||||
<p>在某些地区,习惯在 UTF-8 编码文件的开头用上“BOM”;此名称具有误导性,因为 UTF-8 与字节顺序无关。此标记只是声明该文件以 UTF-8 编码。要读取此类文件,请使用“utf-8-sig”编解码器自动忽略此标记。</p>
|
||||
<section id="unicode-filenames">
|
||||
<h3>Unicode 文件名<a class="headerlink" href="#unicode-filenames" title="永久链接至标题">¶</a></h3>
|
||||
<p>当今大多数操作系统的文件名都支持包含任意 Unicode 字符。通常这是通过将 Unicode 字符串转换为某系统的编码来实现的。如今的 Python 趋向于采用 UTF-8 编码:MacOS 上的 Python 已经在多个版本中采用了 UTF-8,而 Python 3.6 在 Windows 上也改用了 UTF-8。在 Unix 系统中,只有设置了 <code class="docutils literal notranslate"><span class="pre">LANG</span></code> 或 <code class="docutils literal notranslate"><span class="pre">LC_CTYPE</span></code> 环境变量,才会采用某个文件系统编码;否则默认编码还是 UTF-8。</p>
|
||||
<p><a class="reference internal" href="../library/sys.html#sys.getfilesystemencoding" title="sys.getfilesystemencoding"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.getfilesystemencoding()</span></code></a> 函数将返回要在当前系统采用的编码,若想手动进行编码时即可用到,但无需多虑。在打开文件进行读写时,通常只需提供 Unicode 字符串作为文件名,会自动转换为合适的编码格式:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">filename</span> <span class="o">=</span> <span class="s1">'filename</span><span class="se">\u4500</span><span class="s1">abc'</span>
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'blah</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><a class="reference internal" href="../library/os.html#module-os" title="os: Miscellaneous operating system interfaces."><code class="xref py py-mod docutils literal notranslate"><span class="pre">os</span></code></a> 模块中的函数也能接受 Unicode 文件名,如 <a class="reference internal" href="../library/os.html#os.stat" title="os.stat"><code class="xref py py-func docutils literal notranslate"><span class="pre">os.stat()</span></code></a> 。</p>
|
||||
<p><a class="reference internal" href="../library/os.html#os.listdir" title="os.listdir"><code class="xref py py-func docutils literal notranslate"><span class="pre">os.listdir()</span></code></a> 函数将返回文件名,这会引发一个难题:到底应返回文件名的 Unicode 版本,还是应返回已编码的字节串呢?这两种操作 <a class="reference internal" href="../library/os.html#os.listdir" title="os.listdir"><code class="xref py py-func docutils literal notranslate"><span class="pre">os.listdir()</span></code></a> 均可执行,具体取决于给出的目录路径是字节串形式还是 Unicode 字符串。若传入一个 Unicode 字符串作为路径,文件名将用当前文件系统的编码进行解码并返回一个 Unicode 字符串列表,而若传入一个字节串路径则会返回字节串格式的文件名。以下假定默认文件系统编码为 UTF-8,运行以下程序:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">fn</span> <span class="o">=</span> <span class="s1">'filename</span><span class="se">\u4500</span><span class="s1">abc'</span>
|
||||
<span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">fn</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">)</span>
|
||||
<span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">os</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="sa">b</span><span class="s1">'.'</span><span class="p">))</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="s1">'.'</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>将产生以下输出:</p>
|
||||
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python<span class="w"> </span>listdir-test.py
|
||||
<span class="go">[b'filename\xe4\x94\x80abc', ...]</span>
|
||||
<span class="go">['filename\u4500abc', ...]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>第一个列表包含 UTF-8 编码的文件名,第二个列表则包含 Unicode 版本的。</p>
|
||||
<p>请注意,大多时候应该坚持用这些 API 处理 Unicode。字节串 API 应该仅用于可能存在不可解码文件名的系统;现在几乎仅剩 Unix 系统了。</p>
|
||||
</section>
|
||||
<section id="tips-for-writing-unicode-aware-programs">
|
||||
<h3>识别 Unicode 的编程技巧<a class="headerlink" href="#tips-for-writing-unicode-aware-programs" title="永久链接至标题">¶</a></h3>
|
||||
<p>本节提供了一些关于编写 Unicode 处理软件的建议。</p>
|
||||
<p>最重要的技巧如下:</p>
|
||||
<blockquote>
|
||||
<div><p>程序应只在内部处理 Unicode 字符串,尽快对输入数据进行解码,并只在最后对输出进行编码。</p>
|
||||
</div></blockquote>
|
||||
<p>如果尝试编写的处理函数对 Unicode 和字节串形式的字符串都能接受,就会发现组合使用两种不同类型的字符串时,容易产生差错。没办法做到自动编码或解码:如果执行 <code class="docutils literal notranslate"><span class="pre">str</span> <span class="pre">+</span> <span class="pre">bytes</span></code>,则会触发 <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>当要使用的数据来自 Web 浏览器或其他不受信来源时,常用技术是在用该字符串生成命令行之前,或要存入数据库之前,先检查字符串中是否包含非法字符。请仔细检查解码后的字符串,而不是编码格式的字节串数据;有些编码可能具备一些有趣的特性,例如与 ASCII 不是一一对应或不完全兼容。如果输入数据还指定了编码格式,则尤其如此,因为攻击者可以选择一种巧妙的方式将恶意文本隐藏在经过编码的字节流中。</p>
|
||||
<section id="converting-between-file-encodings">
|
||||
<h4>在文件编码格式之间进行转换<a class="headerlink" href="#converting-between-file-encodings" title="永久链接至标题">¶</a></h4>
|
||||
<p><a class="reference internal" href="../library/codecs.html#codecs.StreamRecoder" title="codecs.StreamRecoder"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamRecoder</span></code></a> 类可以在两种编码之间透明地进行转换,参数为编码格式为 #1 的数据流,表现行为则是编码格式为 #2 的数据流。</p>
|
||||
<p>假设输入文件 <em>f</em> 采用 Latin-1 编码格式,即可用 <a class="reference internal" href="../library/codecs.html#codecs.StreamRecoder" title="codecs.StreamRecoder"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamRecoder</span></code></a> 包装后返回 UTF-8 编码的字节串:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">new_f</span> <span class="o">=</span> <span class="n">codecs</span><span class="o">.</span><span class="n">StreamRecoder</span><span class="p">(</span><span class="n">f</span><span class="p">,</span>
|
||||
<span class="c1"># en/decoder: used by read() to encode its results and</span>
|
||||
<span class="c1"># by write() to decode its input.</span>
|
||||
<span class="n">codecs</span><span class="o">.</span><span class="n">getencoder</span><span class="p">(</span><span class="s1">'utf-8'</span><span class="p">),</span> <span class="n">codecs</span><span class="o">.</span><span class="n">getdecoder</span><span class="p">(</span><span class="s1">'utf-8'</span><span class="p">),</span>
|
||||
|
||||
<span class="c1"># reader/writer: used to read and write to the stream.</span>
|
||||
<span class="n">codecs</span><span class="o">.</span><span class="n">getreader</span><span class="p">(</span><span class="s1">'latin-1'</span><span class="p">),</span> <span class="n">codecs</span><span class="o">.</span><span class="n">getwriter</span><span class="p">(</span><span class="s1">'latin-1'</span><span class="p">)</span> <span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="files-in-an-unknown-encoding">
|
||||
<h4>编码格式未知的文件<a class="headerlink" href="#files-in-an-unknown-encoding" title="永久链接至标题">¶</a></h4>
|
||||
<p>若需对文件进行修改,但不知道文件的编码,那该怎么办呢?如果已知编码格式与 ASCII 兼容,并且只想查看或修改 ASCII 部分,则可利用 <code class="docutils literal notranslate"><span class="pre">surrogateescape</span></code> 错误处理 handler 打开文件:</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="n">fname</span><span class="p">,</span> <span class="s1">'r'</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">"ascii"</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s2">"surrogateescape"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># make changes to the string 'data'</span>
|
||||
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">fname</span> <span class="o">+</span> <span class="s1">'.new'</span><span class="p">,</span> <span class="s1">'w'</span><span class="p">,</span>
|
||||
<span class="n">encoding</span><span class="o">=</span><span class="s2">"ascii"</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s2">"surrogateescape"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||||
<span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">surrogateescape</span></code> 错误处理 handler 会把所有非 ASCII 字节解码为 U+DC80 至 U+DCFF 这一特殊范围的码位。当 <code class="docutils literal notranslate"><span class="pre">surrogateescape</span></code> 错误处理 handler用于数据编码并回写时,这些码位将转换回原样。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="id3">
|
||||
<h3>参考文献<a class="headerlink" href="#id3" title="永久链接至标题">¶</a></h3>
|
||||
<p>David Beazley 在 PyCon 2010 上的演讲 <a class="reference external" href="http://pyvideo.org/video/289/pycon-2010--mastering-python-3-io">掌握 Python 3 输入/输出</a> 中,有一节讨论了文本和二进制数据的处理。</p>
|
||||
<p><a class="reference external" href="https://downloads.egenix.com/python/LSM2005-Developing-Unicode-aware-applications-in-Python.pdf">Marc-André Lemburg 演示的PDF 幻灯片“在 Python 中编写支持 Unicode 的应用程序”</a> ,讨论了字符编码问题以及如何国际化和本地化应用程序。这些幻灯片仅涵盖 Python 2.x。</p>
|
||||
<p><a class="reference external" href="http://pyvideo.org/video/1768/the-guts-of-unicode-in-python">Python Unicode 实质</a> 是 Benjamin Peterson 在 PyCon 2013 上的演讲,讨论了 Unicode 在 Python 3.3 中的内部表示。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="acknowledgements">
|
||||
<h2>致谢<a class="headerlink" href="#acknowledgements" title="永久链接至标题">¶</a></h2>
|
||||
<p>本文初稿由 Andrew Kuchling 撰写。此后,Alexander Belopolsky、Georg Brandl、Andrew Kuchling 和 Ezio Melotti 作了进一步修订。</p>
|
||||
<p>感谢以下各位指出本文错误或提出建议:Éric Araujo、Nicholas Bastin、Nick Coghlan、Marius Gedminas、Kent Johnson、Ken Krugler、Marc-André Lemburg、Martin von Löwis、Terry J. Reedy、Serhiy Storchaka , Eryk Sun, Chad Whitacre, Graham Wideman。</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="#">Unicode 指南</a><ul>
|
||||
<li><a class="reference internal" href="#introduction-to-unicode">Unicode 概述</a><ul>
|
||||
<li><a class="reference internal" href="#definitions">定义</a></li>
|
||||
<li><a class="reference internal" href="#encodings">编码</a></li>
|
||||
<li><a class="reference internal" href="#references">参考文献</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#python-s-unicode-support">Python对Unicode的支持</a><ul>
|
||||
<li><a class="reference internal" href="#the-string-type">字符串类型</a></li>
|
||||
<li><a class="reference internal" href="#converting-to-bytes">转换为字节</a></li>
|
||||
<li><a class="reference internal" href="#unicode-literals-in-python-source-code">Python 源代码中的 Unicode 文字</a></li>
|
||||
<li><a class="reference internal" href="#unicode-properties">Unicode属性</a></li>
|
||||
<li><a class="reference internal" href="#comparing-strings">字符串比较</a></li>
|
||||
<li><a class="reference internal" href="#unicode-regular-expressions">Unicode 正则表达式</a></li>
|
||||
<li><a class="reference internal" href="#id2">参考文献</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#reading-and-writing-unicode-data">Unicode 数据的读写</a><ul>
|
||||
<li><a class="reference internal" href="#unicode-filenames">Unicode 文件名</a></li>
|
||||
<li><a class="reference internal" href="#tips-for-writing-unicode-aware-programs">识别 Unicode 的编程技巧</a><ul>
|
||||
<li><a class="reference internal" href="#converting-between-file-encodings">在文件编码格式之间进行转换</a></li>
|
||||
<li><a class="reference internal" href="#files-in-an-unknown-encoding">编码格式未知的文件</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#id3">参考文献</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#acknowledgements">致谢</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="sorting.html"
|
||||
title="上一章">排序指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="urllib2.html"
|
||||
title="下一章">如何利用 urllib 包获取网络资源</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/howto/unicode.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="urllib2.html" title="如何利用 urllib 包获取网络资源"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="sorting.html" title="排序指南"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
713
web/python-docs/howto/urllib2.html
Normal file
713
web/python-docs/howto/urllib2.html
Normal file
@@ -0,0 +1,713 @@
|
||||
|
||||
<!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>如何利用 urllib 包获取网络资源 — 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="argparse 教程" href="argparse.html" />
|
||||
<link rel="prev" title="Unicode 指南" href="unicode.html" />
|
||||
<link rel="canonical" href="https://docs.python.org/3/howto/urllib2.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="#">如何利用 urllib 包获取网络资源</a><ul>
|
||||
<li><a class="reference internal" href="#introduction">概述</a></li>
|
||||
<li><a class="reference internal" href="#fetching-urls">获取 URL 资源</a><ul>
|
||||
<li><a class="reference internal" href="#data">数据</a></li>
|
||||
<li><a class="reference internal" href="#headers">HTTP 头部信息</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#handling-exceptions">异常的处理</a><ul>
|
||||
<li><a class="reference internal" href="#urlerror">URLError</a></li>
|
||||
<li><a class="reference internal" href="#httperror">HTTPError</a><ul>
|
||||
<li><a class="reference internal" href="#error-codes">错误代码</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#wrapping-it-up">总之</a><ul>
|
||||
<li><a class="reference internal" href="#number-1">第一种方案</a></li>
|
||||
<li><a class="reference internal" href="#number-2">第二种方案</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#info-and-geturl">info 和 geturl 方法</a></li>
|
||||
<li><a class="reference internal" href="#openers-and-handlers">Opener 和 Handler</a></li>
|
||||
<li><a class="reference internal" href="#id5">基本认证</a></li>
|
||||
<li><a class="reference internal" href="#proxies">代理</a></li>
|
||||
<li><a class="reference internal" href="#sockets-and-layers">套接字与分层</a></li>
|
||||
<li><a class="reference internal" href="#footnotes">备注</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="unicode.html"
|
||||
title="上一章">Unicode 指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="argparse.html"
|
||||
title="下一章">argparse 教程</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/howto/urllib2.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/howto/urllib2.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="argparse.html" title="argparse 教程"
|
||||
accesskey="N">下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="unicode.html" title="Unicode 指南"
|
||||
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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 指南</a> »</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="howto-fetch-internet-resources-using-the-urllib-package">
|
||||
<span id="urllib-howto"></span><h1>如何利用 urllib 包获取网络资源<a class="headerlink" href="#howto-fetch-internet-resources-using-the-urllib-package" title="永久链接至标题">¶</a></h1>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">作者</dt>
|
||||
<dd class="field-odd"><p><a class="reference external" href="http://www.voidspace.org.uk/python/index.shtml">Michael Foord</a></p>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p>这份 HOWTO 文档的早期版本有一份法语的译文,可在 <a class="reference external" href="http://www.voidspace.org.uk/python/articles/urllib2_francais.shtml">urllib2 - Le Manuel manquant</a> 处查阅。</p>
|
||||
</div>
|
||||
<section id="introduction">
|
||||
<h2>概述<a class="headerlink" href="#introduction" title="永久链接至标题">¶</a></h2>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Related Articles</p>
|
||||
<p>关于如何用 Python 获取 web 资源,以下文章或许也很有用:</p>
|
||||
<ul>
|
||||
<li><p><a class="reference external" href="http://www.voidspace.org.uk/python/articles/authentication.shtml">基础的身份认证</a></p>
|
||||
<blockquote>
|
||||
<div><p><em>基本认证</em> 的教程,带有一些 Python 示例。</p>
|
||||
</div></blockquote>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
<p><strong>urllib.request</strong> 是用于获取 URL (统一资源定位符)的 Python 模块。它以 <em>urlopen</em> 函数的形式提供了一个非常简单的接口,能用不同的协议获取 URL。同时它还为处理各种常见情形提供了一个稍微复杂一些的接口——比如:基础身份认证、cookies、代理等等。这些功能是由名为 handlers 和 opener 的对象提供的。</p>
|
||||
<p>urllib.request 支持多种 "URL 方案" (通过 URL中 <code class="docutils literal notranslate"><span class="pre">":"</span></code> 之前的字符串加以区分——如 <code class="docutils literal notranslate"><span class="pre">"ftp://python.org/"</span></code> 中的 <code class="docutils literal notranslate"><span class="pre">"ftp"</span></code>)即为采用其关联网络协议(FTP、HTTP 之类)的 URL 方案 。本教程重点关注最常用的 HTTP 场景。</p>
|
||||
<p>对于简单场景而言, <em>urlopen</em> 用起来十分容易。但只要在打开 HTTP URL 时遇到错误或非常情况,就需要对超文本传输协议有所了解才行。最全面、最权威的 HTTP 参考是 <span class="target" id="index-8"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc2616.html"><strong>RFC 2616</strong></a> 。那是一份技术文档,并没有追求可读性。本 文旨在说明 <em>urllib</em> 的用法,为了便于阅读也附带了足够详细的 HTTP 信息。本文并不是为了替代 <a class="reference internal" href="../library/urllib.request.html#module-urllib.request" title="urllib.request: Extensible library for opening URLs."><code class="xref py py-mod docutils literal notranslate"><span class="pre">urllib.request</span></code></a> 文档,只是其补充说明而已。</p>
|
||||
</section>
|
||||
<section id="fetching-urls">
|
||||
<h2>获取 URL 资源<a class="headerlink" href="#fetching-urls" title="永久链接至标题">¶</a></h2>
|
||||
<p>urllib.request 最简单的使用方式如下所示:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">urllib.request</span>
|
||||
<span class="k">with</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s1">'http://python.org/'</span><span class="p">)</span> <span class="k">as</span> <span class="n">response</span><span class="p">:</span>
|
||||
<span class="n">html</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>如果想通过 URL 获取资源并临时存储一下,可以采用 <a class="reference internal" href="../library/shutil.html#shutil.copyfileobj" title="shutil.copyfileobj"><code class="xref py py-func docutils literal notranslate"><span class="pre">shutil.copyfileobj()</span></code></a> 和 <a class="reference internal" href="../library/tempfile.html#tempfile.NamedTemporaryFile" title="tempfile.NamedTemporaryFile"><code class="xref py py-func docutils literal notranslate"><span class="pre">tempfile.NamedTemporaryFile()</span></code></a> 函数:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">shutil</span>
|
||||
<span class="kn">import</span> <span class="nn">tempfile</span>
|
||||
<span class="kn">import</span> <span class="nn">urllib.request</span>
|
||||
|
||||
<span class="k">with</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s1">'http://python.org/'</span><span class="p">)</span> <span class="k">as</span> <span class="n">response</span><span class="p">:</span>
|
||||
<span class="k">with</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">NamedTemporaryFile</span><span class="p">(</span><span class="n">delete</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="k">as</span> <span class="n">tmp_file</span><span class="p">:</span>
|
||||
<span class="n">shutil</span><span class="o">.</span><span class="n">copyfileobj</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">tmp_file</span><span class="p">)</span>
|
||||
|
||||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">tmp_file</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> <span class="k">as</span> <span class="n">html</span><span class="p">:</span>
|
||||
<span class="k">pass</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>urllib 的很多用法就是这么简单(注意 URL 不仅可以 http: 开头,还可以是 ftp: 、file: 等)。不过本教程的目的是介绍更加复杂的应用场景,重点还是关注 HTTP。</p>
|
||||
<p>HTTP 以请求和响应为基础——客户端生成请求,服务器发送响应。urllib.request 用 <code class="docutils literal notranslate"><span class="pre">Request</span></code> 对象来表示要生成的 HTTP 请求。最简单的形式就是创建一个 Request 对象,指定了想要获取的 URL。用这个 Request 对象作为参数调用 <code class="docutils literal notranslate"><span class="pre">urlopen</span></code> ,将会返回该 URL 的响应对象。响应对象类似于文件对象,就是说可以对其调用 <code class="docutils literal notranslate"><span class="pre">.read()</span></code> 之类的命令:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">urllib.request</span>
|
||||
|
||||
<span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="s1">'http://www.voidspace.org.uk'</span><span class="p">)</span>
|
||||
<span class="k">with</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="k">as</span> <span class="n">response</span><span class="p">:</span>
|
||||
<span class="n">the_page</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>请注意,urllib.request 用同一个 Request 接口处理所有 URL 方案。比如可生成 FTP 请求如下:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="s1">'ftp://example.com/'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>就 HTTP 而言,Request 对象能够做两件额外的事情:首先可以把数据传给服务器。其次,可以将 <em>有关</em> 数据或请求本身的额外信息(metadata)传给服务器——这些信息将会作为 HTTP “头部”数据发送。下面依次看下。</p>
|
||||
<section id="data">
|
||||
<h3>数据<a class="headerlink" href="#data" title="永久链接至标题">¶</a></h3>
|
||||
<p>有时需要向某个 URL 发送数据,通常此 URL 会指向某个CGI(通用网关接口)脚本或其他 web 应用。对于 HTTP 而言,这通常会用所谓的 <strong>POST</strong> 请求来完成。当要把 Web 页填写的 HTML 表单提交时,浏览器通常会执行此操作。但并不是所有的 POST 都来自表单:可以用 POST 方式传输任何数据到自己的应用上。对于通常的 HTML 表单,数据需要以标准的方式编码,然后作为 <code class="docutils literal notranslate"><span class="pre">data</span></code> 参数传给 Request 对象。编码过程是用 <a class="reference internal" href="../library/urllib.parse.html#module-urllib.parse" title="urllib.parse: Parse URLs into or assemble them from components."><code class="xref py py-mod docutils literal notranslate"><span class="pre">urllib.parse</span></code></a> 库的函数完成的:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">urllib.parse</span>
|
||||
<span class="kn">import</span> <span class="nn">urllib.request</span>
|
||||
|
||||
<span class="n">url</span> <span class="o">=</span> <span class="s1">'http://www.someserver.com/cgi-bin/register.cgi'</span>
|
||||
<span class="n">values</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'name'</span> <span class="p">:</span> <span class="s1">'Michael Foord'</span><span class="p">,</span>
|
||||
<span class="s1">'location'</span> <span class="p">:</span> <span class="s1">'Northampton'</span><span class="p">,</span>
|
||||
<span class="s1">'language'</span> <span class="p">:</span> <span class="s1">'Python'</span> <span class="p">}</span>
|
||||
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">values</span><span class="p">)</span>
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">)</span> <span class="c1"># data should be bytes</span>
|
||||
<span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
|
||||
<span class="k">with</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="k">as</span> <span class="n">response</span><span class="p">:</span>
|
||||
<span class="n">the_page</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>请注意,有时还需要采用其他编码,比如由 HTML 表单上传文件——更多细节请参见 <a class="reference external" href="https://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13">HTML 规范,提交表单</a> 。</p>
|
||||
<p>如果不传递 <code class="docutils literal notranslate"><span class="pre">data</span></code> 参数,urllib 将采用 <strong>GET</strong> 请求。GET 和 POST 请求有一点不同,POST 请求往往具有“副作用”,他们会以某种方式改变系统的状态。例如,从网站下一个订单,购买一大堆罐装垃圾并运送到家。 尽管 HTTP 标准明确指出 POST <em>总是</em> 要导致副作用,而 GET 请求 <em>从来不会</em> 导致副作用。但没有什么办法能阻止 GET 和 POST 请求的副作用。数据也可以在 HTTP GET 请求中传递,只要把数据编码到 URL 中即可。</p>
|
||||
<p>做法如下所示:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">urllib.request</span>
|
||||
<span class="gp">>>> </span><span class="kn">import</span> <span class="nn">urllib.parse</span>
|
||||
<span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<span class="gp">>>> </span><span class="n">data</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'Somebody Here'</span>
|
||||
<span class="gp">>>> </span><span class="n">data</span><span class="p">[</span><span class="s1">'location'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'Northampton'</span>
|
||||
<span class="gp">>>> </span><span class="n">data</span><span class="p">[</span><span class="s1">'language'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'Python'</span>
|
||||
<span class="gp">>>> </span><span class="n">url_values</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">url_values</span><span class="p">)</span> <span class="c1"># The order may differ from below. </span>
|
||||
<span class="go">name=Somebody+Here&language=Python&location=Northampton</span>
|
||||
<span class="gp">>>> </span><span class="n">url</span> <span class="o">=</span> <span class="s1">'http://www.example.com/example.cgi'</span>
|
||||
<span class="gp">>>> </span><span class="n">full_url</span> <span class="o">=</span> <span class="n">url</span> <span class="o">+</span> <span class="s1">'?'</span> <span class="o">+</span> <span class="n">url_values</span>
|
||||
<span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">full_url</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>请注意,完整的 URL 是通过在其中添加 <code class="docutils literal notranslate"><span class="pre">?</span></code> 创建的,后面跟着经过编码的数据。</p>
|
||||
</section>
|
||||
<section id="headers">
|
||||
<h3>HTTP 头部信息<a class="headerlink" href="#headers" title="永久链接至标题">¶</a></h3>
|
||||
<p>下面介绍一个具体的 HTTP 头部信息,以此说明如何在 HTTP 请求加入头部信息。</p>
|
||||
<p>有些网站 <a class="footnote-reference brackets" href="#id8" id="id1">1</a> 不愿被程序浏览到,或者要向不同的浏览器发送不同版本 <a class="footnote-reference brackets" href="#id9" id="id2">2</a> 的网页。默认情况下,urllib 将自身标识为“Python-urllib/xy”(其中 <code class="docutils literal notranslate"><span class="pre">x</span></code> 、 <code class="docutils literal notranslate"><span class="pre">y</span></code> 是 Python 版本的主、次版本号,例如 <code class="docutils literal notranslate"><span class="pre">Python-urllib/2.5</span></code>),这可能会让网站不知所措,或者干脆就使其无法正常工作。浏览器是通过头部信息 <code class="docutils literal notranslate"><span class="pre">User-Agent</span></code> <a class="footnote-reference brackets" href="#id10" id="id3">3</a> 来标识自己的。在创建 Request 对象时,可以传入字典形式的头部信息。以下示例将生成与之前相同的请求,只是将自身标识为某个版本的 Internet Explorer <a class="footnote-reference brackets" href="#id11" id="id4">4</a> :</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">urllib.parse</span>
|
||||
<span class="kn">import</span> <span class="nn">urllib.request</span>
|
||||
|
||||
<span class="n">url</span> <span class="o">=</span> <span class="s1">'http://www.someserver.com/cgi-bin/register.cgi'</span>
|
||||
<span class="n">user_agent</span> <span class="o">=</span> <span class="s1">'Mozilla/5.0 (Windows NT 6.1; Win64; x64)'</span>
|
||||
<span class="n">values</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'name'</span><span class="p">:</span> <span class="s1">'Michael Foord'</span><span class="p">,</span>
|
||||
<span class="s1">'location'</span><span class="p">:</span> <span class="s1">'Northampton'</span><span class="p">,</span>
|
||||
<span class="s1">'language'</span><span class="p">:</span> <span class="s1">'Python'</span> <span class="p">}</span>
|
||||
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'User-Agent'</span><span class="p">:</span> <span class="n">user_agent</span><span class="p">}</span>
|
||||
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">values</span><span class="p">)</span>
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">)</span>
|
||||
<span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">headers</span><span class="p">)</span>
|
||||
<span class="k">with</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="k">as</span> <span class="n">response</span><span class="p">:</span>
|
||||
<span class="n">the_page</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>响应对象也有两个很有用的方法。请参阅有关 <a class="reference internal" href="#info-and-geturl">info 和 geturl</a> 部分,了解出现问题时会发生什么。</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="handling-exceptions">
|
||||
<h2>异常的处理<a class="headerlink" href="#handling-exceptions" title="永久链接至标题">¶</a></h2>
|
||||
<p>如果 <em>urlopen</em> 无法处理响应信息,就会触发 <code class="xref py py-exc docutils literal notranslate"><span class="pre">URLError</span></code> 。尽管与通常的 Python API 一样,也可能触发 <a class="reference internal" href="../library/exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">ValueError</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><code class="xref py py-exc docutils literal notranslate"><span class="pre">HTTPError</span></code> 是 <code class="xref py py-exc docutils literal notranslate"><span class="pre">URLError</span></code> 的子类,当 URL 是 HTTP 的情况时将会触发。</p>
|
||||
<p>上述异常类是从 <a class="reference internal" href="../library/urllib.error.html#module-urllib.error" title="urllib.error: Exception classes raised by urllib.request."><code class="xref py py-mod docutils literal notranslate"><span class="pre">urllib.error</span></code></a> 模块中导出的。</p>
|
||||
<section id="urlerror">
|
||||
<h3>URLError<a class="headerlink" href="#urlerror" title="永久链接至标题">¶</a></h3>
|
||||
<p>触发 URLError 的原因,通常是网络不通(或者没有到指定服务器的路由),或者指定的服务器不存在。这时触发的异常会带有一个 reason 属性,是一个包含错误代码和文本错误信息的元组。</p>
|
||||
<p>例如:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="s1">'http://www.pretend_server.org'</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="k">try</span><span class="p">:</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>
|
||||
<span class="gp">... </span><span class="k">except</span> <span class="n">urllib</span><span class="o">.</span><span class="n">error</span><span class="o">.</span><span class="n">URLError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">reason</span><span class="p">)</span>
|
||||
<span class="gp">...</span>
|
||||
<span class="go">(4, 'getaddrinfo failed')</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="httperror">
|
||||
<h3>HTTPError<a class="headerlink" href="#httperror" title="永久链接至标题">¶</a></h3>
|
||||
<p>从服务器返回的每个 HTTP 响应都包含一个数字的 “状态码”。有时该状态码表明服务器无法完成该请求。默认的处理函数将会处理这其中的一部分响应。如若响应是“redirection”,这是要求客户端从另一 URL 处获取数据,urllib 将会自行处理。对于那些无法处理的状况,urlopen 将会引发 <code class="xref py py-exc docutils literal notranslate"><span class="pre">HTTPError</span></code> 。典型的错误包括:“404”(页面无法找到)、“403”(请求遭拒绝)和“401”(需要身份认证)。</p>
|
||||
<p>全部的 HTTP 错误码请参阅 <span class="target" id="index-9"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc2616.html"><strong>RFC 2616</strong></a> 。</p>
|
||||
<p><code class="xref py py-exc docutils literal notranslate"><span class="pre">HTTPError</span></code> 实例将包含一个整数型的“code”属性,对应于服务器发来的错误。</p>
|
||||
<section id="error-codes">
|
||||
<h4>错误代码<a class="headerlink" href="#error-codes" title="永久链接至标题">¶</a></h4>
|
||||
<p>由于默认处理函数会自行处理重定向(300 以内的错误码),而且 100--299 的状态码表示成功,因此通常只会出现 400--599 的错误码。</p>
|
||||
<p><a class="reference internal" href="../library/http.server.html#http.server.BaseHTTPRequestHandler.responses" title="http.server.BaseHTTPRequestHandler.responses"><code class="xref py py-attr docutils literal notranslate"><span class="pre">http.server.BaseHTTPRequestHandler.responses</span></code></a> 是很有用的响应码字典,其中给出了 <span class="target" id="index-10"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc2616.html"><strong>RFC 2616</strong></a> 用到的所有响应代码。为方便起见,将此字典转载如下:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># Table mapping response codes to messages; entries have the</span>
|
||||
<span class="c1"># form {code: (shortmessage, longmessage)}.</span>
|
||||
<span class="n">responses</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="mi">100</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Continue'</span><span class="p">,</span> <span class="s1">'Request received, please continue'</span><span class="p">),</span>
|
||||
<span class="mi">101</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Switching Protocols'</span><span class="p">,</span>
|
||||
<span class="s1">'Switching to new protocol; obey Upgrade header'</span><span class="p">),</span>
|
||||
|
||||
<span class="mi">200</span><span class="p">:</span> <span class="p">(</span><span class="s1">'OK'</span><span class="p">,</span> <span class="s1">'Request fulfilled, document follows'</span><span class="p">),</span>
|
||||
<span class="mi">201</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Created'</span><span class="p">,</span> <span class="s1">'Document created, URL follows'</span><span class="p">),</span>
|
||||
<span class="mi">202</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Accepted'</span><span class="p">,</span>
|
||||
<span class="s1">'Request accepted, processing continues off-line'</span><span class="p">),</span>
|
||||
<span class="mi">203</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Non-Authoritative Information'</span><span class="p">,</span> <span class="s1">'Request fulfilled from cache'</span><span class="p">),</span>
|
||||
<span class="mi">204</span><span class="p">:</span> <span class="p">(</span><span class="s1">'No Content'</span><span class="p">,</span> <span class="s1">'Request fulfilled, nothing follows'</span><span class="p">),</span>
|
||||
<span class="mi">205</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Reset Content'</span><span class="p">,</span> <span class="s1">'Clear input form for further input.'</span><span class="p">),</span>
|
||||
<span class="mi">206</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Partial Content'</span><span class="p">,</span> <span class="s1">'Partial content follows.'</span><span class="p">),</span>
|
||||
|
||||
<span class="mi">300</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Multiple Choices'</span><span class="p">,</span>
|
||||
<span class="s1">'Object has several resources -- see URI list'</span><span class="p">),</span>
|
||||
<span class="mi">301</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Moved Permanently'</span><span class="p">,</span> <span class="s1">'Object moved permanently -- see URI list'</span><span class="p">),</span>
|
||||
<span class="mi">302</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Found'</span><span class="p">,</span> <span class="s1">'Object moved temporarily -- see URI list'</span><span class="p">),</span>
|
||||
<span class="mi">303</span><span class="p">:</span> <span class="p">(</span><span class="s1">'See Other'</span><span class="p">,</span> <span class="s1">'Object moved -- see Method and URL list'</span><span class="p">),</span>
|
||||
<span class="mi">304</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Not Modified'</span><span class="p">,</span>
|
||||
<span class="s1">'Document has not changed since given time'</span><span class="p">),</span>
|
||||
<span class="mi">305</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Use Proxy'</span><span class="p">,</span>
|
||||
<span class="s1">'You must use proxy specified in Location to access this '</span>
|
||||
<span class="s1">'resource.'</span><span class="p">),</span>
|
||||
<span class="mi">307</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Temporary Redirect'</span><span class="p">,</span>
|
||||
<span class="s1">'Object moved temporarily -- see URI list'</span><span class="p">),</span>
|
||||
|
||||
<span class="mi">400</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Bad Request'</span><span class="p">,</span>
|
||||
<span class="s1">'Bad request syntax or unsupported method'</span><span class="p">),</span>
|
||||
<span class="mi">401</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Unauthorized'</span><span class="p">,</span>
|
||||
<span class="s1">'No permission -- see authorization schemes'</span><span class="p">),</span>
|
||||
<span class="mi">402</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Payment Required'</span><span class="p">,</span>
|
||||
<span class="s1">'No payment -- see charging schemes'</span><span class="p">),</span>
|
||||
<span class="mi">403</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Forbidden'</span><span class="p">,</span>
|
||||
<span class="s1">'Request forbidden -- authorization will not help'</span><span class="p">),</span>
|
||||
<span class="mi">404</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Not Found'</span><span class="p">,</span> <span class="s1">'Nothing matches the given URI'</span><span class="p">),</span>
|
||||
<span class="mi">405</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Method Not Allowed'</span><span class="p">,</span>
|
||||
<span class="s1">'Specified method is invalid for this server.'</span><span class="p">),</span>
|
||||
<span class="mi">406</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Not Acceptable'</span><span class="p">,</span> <span class="s1">'URI not available in preferred format.'</span><span class="p">),</span>
|
||||
<span class="mi">407</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Proxy Authentication Required'</span><span class="p">,</span> <span class="s1">'You must authenticate with '</span>
|
||||
<span class="s1">'this proxy before proceeding.'</span><span class="p">),</span>
|
||||
<span class="mi">408</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Request Timeout'</span><span class="p">,</span> <span class="s1">'Request timed out; try again later.'</span><span class="p">),</span>
|
||||
<span class="mi">409</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Conflict'</span><span class="p">,</span> <span class="s1">'Request conflict.'</span><span class="p">),</span>
|
||||
<span class="mi">410</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Gone'</span><span class="p">,</span>
|
||||
<span class="s1">'URI no longer exists and has been permanently removed.'</span><span class="p">),</span>
|
||||
<span class="mi">411</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Length Required'</span><span class="p">,</span> <span class="s1">'Client must specify Content-Length.'</span><span class="p">),</span>
|
||||
<span class="mi">412</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Precondition Failed'</span><span class="p">,</span> <span class="s1">'Precondition in headers is false.'</span><span class="p">),</span>
|
||||
<span class="mi">413</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Request Entity Too Large'</span><span class="p">,</span> <span class="s1">'Entity is too large.'</span><span class="p">),</span>
|
||||
<span class="mi">414</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Request-URI Too Long'</span><span class="p">,</span> <span class="s1">'URI is too long.'</span><span class="p">),</span>
|
||||
<span class="mi">415</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Unsupported Media Type'</span><span class="p">,</span> <span class="s1">'Entity body in unsupported format.'</span><span class="p">),</span>
|
||||
<span class="mi">416</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Requested Range Not Satisfiable'</span><span class="p">,</span>
|
||||
<span class="s1">'Cannot satisfy request range.'</span><span class="p">),</span>
|
||||
<span class="mi">417</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Expectation Failed'</span><span class="p">,</span>
|
||||
<span class="s1">'Expect condition could not be satisfied.'</span><span class="p">),</span>
|
||||
|
||||
<span class="mi">500</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Internal Server Error'</span><span class="p">,</span> <span class="s1">'Server got itself in trouble'</span><span class="p">),</span>
|
||||
<span class="mi">501</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Not Implemented'</span><span class="p">,</span>
|
||||
<span class="s1">'Server does not support this operation'</span><span class="p">),</span>
|
||||
<span class="mi">502</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Bad Gateway'</span><span class="p">,</span> <span class="s1">'Invalid responses from another server/proxy.'</span><span class="p">),</span>
|
||||
<span class="mi">503</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Service Unavailable'</span><span class="p">,</span>
|
||||
<span class="s1">'The server cannot process the request due to a high load'</span><span class="p">),</span>
|
||||
<span class="mi">504</span><span class="p">:</span> <span class="p">(</span><span class="s1">'Gateway Timeout'</span><span class="p">,</span>
|
||||
<span class="s1">'The gateway server did not receive a timely response'</span><span class="p">),</span>
|
||||
<span class="mi">505</span><span class="p">:</span> <span class="p">(</span><span class="s1">'HTTP Version Not Supported'</span><span class="p">,</span> <span class="s1">'Cannot fulfill request.'</span><span class="p">),</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>当触发错误时,服务器通过返回 HTTP 错误码 <em>和</em> 错误页面进行响应。可以将 <code class="xref py py-exc docutils literal notranslate"><span class="pre">HTTPError</span></code> 实例用作返回页面的响应。这意味着除了 code 属性之外,错误对象还像 <code class="docutils literal notranslate"><span class="pre">urllib.response</span></code> 模块返回的那样具有 read、geturl 和 info 方法:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="s1">'http://www.python.org/fish.html'</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">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>
|
||||
<span class="gp">... </span><span class="k">except</span> <span class="n">urllib</span><span class="o">.</span><span class="n">error</span><span class="o">.</span><span class="n">HTTPError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">code</span><span class="p">)</span>
|
||||
<span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">read</span><span class="p">())</span>
|
||||
<span class="gp">...</span>
|
||||
<span class="go">404</span>
|
||||
<span class="go">b'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"</span>
|
||||
<span class="go"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n\n\n<html</span>
|
||||
<span class="go"> ...</span>
|
||||
<span class="go"> <title>Page Not Found</title>\n</span>
|
||||
<span class="go"> ...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="wrapping-it-up">
|
||||
<h3>总之<a class="headerlink" href="#wrapping-it-up" title="永久链接至标题">¶</a></h3>
|
||||
<p>若要准备处理 <code class="xref py py-exc docutils literal notranslate"><span class="pre">HTTPError</span></code> <em>或</em> <code class="xref py py-exc docutils literal notranslate"><span class="pre">URLError</span></code> ,有两种简单的方案。推荐使用第二种方案。</p>
|
||||
<section id="number-1">
|
||||
<h4>第一种方案<a class="headerlink" href="#number-1" title="永久链接至标题">¶</a></h4>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">urllib.request</span> <span class="kn">import</span> <span class="n">Request</span><span class="p">,</span> <span class="n">urlopen</span>
|
||||
<span class="kn">from</span> <span class="nn">urllib.error</span> <span class="kn">import</span> <span class="n">URLError</span><span class="p">,</span> <span class="n">HTTPError</span>
|
||||
<span class="n">req</span> <span class="o">=</span> <span class="n">Request</span><span class="p">(</span><span class="n">someurl</span><span class="p">)</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">response</span> <span class="o">=</span> <span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">HTTPError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'The server couldn</span><span class="se">\'</span><span class="s1">t fulfill the request.'</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'Error code: '</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">code</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">URLError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'We failed to reach a server.'</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'Reason: '</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">reason</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># everything is fine</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">except</span> <span class="pre">HTTPError</span></code> <em>必须</em> 首先处理,否则 <code class="docutils literal notranslate"><span class="pre">except</span> <span class="pre">URLError</span></code> 将会 <em>同时</em> 捕获 <code class="xref py py-exc docutils literal notranslate"><span class="pre">HTTPError</span></code> 。</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="number-2">
|
||||
<h4>第二种方案<a class="headerlink" href="#number-2" title="永久链接至标题">¶</a></h4>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">urllib.request</span> <span class="kn">import</span> <span class="n">Request</span><span class="p">,</span> <span class="n">urlopen</span>
|
||||
<span class="kn">from</span> <span class="nn">urllib.error</span> <span class="kn">import</span> <span class="n">URLError</span>
|
||||
<span class="n">req</span> <span class="o">=</span> <span class="n">Request</span><span class="p">(</span><span class="n">someurl</span><span class="p">)</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">response</span> <span class="o">=</span> <span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">URLError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="s1">'reason'</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'We failed to reach a server.'</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'Reason: '</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">reason</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="s1">'code'</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'The server couldn</span><span class="se">\'</span><span class="s1">t fulfill the request.'</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s1">'Error code: '</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">code</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># everything is fine</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="info-and-geturl">
|
||||
<h2>info 和 geturl 方法<a class="headerlink" href="#info-and-geturl" title="永久链接至标题">¶</a></h2>
|
||||
<p>由 urlopen (或者 <code class="xref py py-exc docutils literal notranslate"><span class="pre">HTTPError</span></code> 实例)所返回的响应包含两个有用的方法: <code class="xref py py-meth docutils literal notranslate"><span class="pre">info()</span></code> 和 <code class="xref py py-meth docutils literal notranslate"><span class="pre">geturl()</span></code>,该响应由模块 <a class="reference internal" href="../library/urllib.request.html#module-urllib.response" title="urllib.response: Response classes used by urllib."><code class="xref py py-mod docutils literal notranslate"><span class="pre">urllib.response</span></code></a> 定义。</p>
|
||||
<p><strong>geturl</strong> ——返回所获取页面的真实 URL。该方法很有用,因为 <code class="docutils literal notranslate"><span class="pre">urlopen</span></code> (或 opener 对象)可能已经经过了一次重定向。已获取页面的 URL 未必就是所请求的 URL 。</p>
|
||||
<p><strong>info</strong> - 该方法返回一个类似字典的对象,描述了所获取的页面,特别是由服务器送出的头部信息(headers) 。目前它是一个 <code class="xref py py-class docutils literal notranslate"><span class="pre">http.client.HTTPMessage</span></code> 实例。</p>
|
||||
<p>典型的 HTTP 头部信息包括“Content-length”、“Content-type”等。有关 HTTP 头部信息的清单,包括含义和用途的简要说明,请参阅 <a class="reference external" href="http://jkorpela.fi/http.html">HTTP Header 快速参考</a> 。</p>
|
||||
</section>
|
||||
<section id="openers-and-handlers">
|
||||
<h2>Opener 和 Handler<a class="headerlink" href="#openers-and-handlers" title="永久链接至标题">¶</a></h2>
|
||||
<p>当获取 URL 时,会用到了一个 opener(一个类名可能经过混淆的 <a class="reference internal" href="../library/urllib.request.html#urllib.request.OpenerDirector" title="urllib.request.OpenerDirector"><code class="xref py py-class docutils literal notranslate"><span class="pre">urllib.request.OpenerDirector</span></code></a> 的实例)。通常一直会用默认的 opener ——通过 <code class="docutils literal notranslate"><span class="pre">urlopen</span></code> ——但也可以创建自定义的 opener 。opener 会用到 handler。所有的“繁重工作”都由 handler 完成。每种 handler 知道某种 URL 方案(http、ftp 等)的 URL 的打开方式,或是某方面 URL 的打开方式,例如 HTTP 重定向或 HTTP cookie。</p>
|
||||
<p>若要用已安装的某个 handler 获取 URL,需要创建一个 opener 对象,例如处理 cookie 的 opener,或对重定向不做处理的 opener。</p>
|
||||
<p>若要创建 opener,请实例化一个 <code class="docutils literal notranslate"><span class="pre">OpenerDirector</span></code> ,然后重复调用 <code class="docutils literal notranslate"><span class="pre">.add_handler(some_handler_instance)</span></code> 。</p>
|
||||
<p>或者也可以用 <code class="docutils literal notranslate"><span class="pre">build_opener</span></code> ,这是个用单次调用创建 opener 对象的便捷函数。<code class="docutils literal notranslate"><span class="pre">build_opener</span></code> 默认会添加几个 handler,不过还提供了一种快速添加和/或覆盖默认 handler 的方法。</p>
|
||||
<p>可能还需要其他类型的 handler,以便处理代理、身份认证和其他常见但稍微特殊的情况。</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">install_opener</span></code> 可用于让 <code class="docutils literal notranslate"><span class="pre">opener</span></code> 对象成为(全局)默认 opener。这意味着调用 <code class="docutils literal notranslate"><span class="pre">urlopen</span></code> 时会采用已安装的 opener。</p>
|
||||
<p>opener 对象带有一个 <code class="docutils literal notranslate"><span class="pre">`open</span></code> 方法,可供直接调用以获取 url,方式与 <code class="docutils literal notranslate"><span class="pre">urlopen</span></code> 函数相同。除非是为了调用方便,否则没必要去调用 <code class="docutils literal notranslate"><span class="pre">install_opener</span></code> 。</p>
|
||||
</section>
|
||||
<section id="id5">
|
||||
<h2>基本认证<a class="headerlink" href="#id5" title="永久链接至标题">¶</a></h2>
|
||||
<p>为了说明 handler 的创建和安装过程,会用到 <code class="docutils literal notranslate"><span class="pre">HTTPBasicAuthHandler</span></code> 。有关该主题的更详细的介绍——包括基本身份认证的工作原理——请参阅 <a class="reference external" href="http://www.voidspace.org.uk/python/articles/authentication.shtml">Basic Authentication Tutorial</a> 。</p>
|
||||
<p>如果需要身份认证,服务器会发送一条请求身份认证的头部信息(以及 401 错误代码)。这条信息中指明了身份认证方式和“安全区域(realm)”。格式如下所示:<code class="docutils literal notranslate"><span class="pre">WWW-Authenticate:</span> <span class="pre">SCHEME</span> <span class="pre">realm="REALM"</span></code> 。</p>
|
||||
<p>例如</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>WWW-Authenticate: Basic realm="cPanel Users"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>然后,客户端应重试发起请求,请求数据中的头部信息应包含安全区域对应的用户名和密码。这就是“基本身份认证”。为了简化此过程,可以创建 <code class="docutils literal notranslate"><span class="pre">HTTPBasicAuthHandler</span></code> 的一个实例及使用它的 opener。</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">HTTPBasicAuthHandler</span></code> 用一个名为密码管理器的对象来管理 URL、安全区域与密码、用户名之间的映射关系。如果知道确切的安全区域(来自服务器发送的身份认证头部信息),那就可以用到 <code class="docutils literal notranslate"><span class="pre">HTTPPasswordMgr</span></code> 。通常人们并不关心安全区域是什么,这时用 <code class="docutils literal notranslate"><span class="pre">HTTPPasswordMgrWithDefaultRealm</span></code> 就很方便,允许为 URL 指定默认的用户名和密码。当没有为某个安全区域提供用户名和密码时,就会用到默认值。下面用 <code class="docutils literal notranslate"><span class="pre">None</span></code> 作为 <code class="docutils literal notranslate"><span class="pre">add_password</span></code> 方法的安全区域参数,表明采用默认用户名和密码。</p>
|
||||
<p>首先需要身份认证的是顶级 URL。比传给 .add_password() 的 URL 级别“更深”的 URL 也会得以匹配:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="c1"># create a password manager</span>
|
||||
<span class="n">password_mgr</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">HTTPPasswordMgrWithDefaultRealm</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># Add the username and password.</span>
|
||||
<span class="c1"># If we knew the realm, we could use it instead of None.</span>
|
||||
<span class="n">top_level_url</span> <span class="o">=</span> <span class="s2">"http://example.com/foo/"</span>
|
||||
<span class="n">password_mgr</span><span class="o">.</span><span class="n">add_password</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">top_level_url</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
|
||||
|
||||
<span class="n">handler</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">HTTPBasicAuthHandler</span><span class="p">(</span><span class="n">password_mgr</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># create "opener" (OpenerDirector instance)</span>
|
||||
<span class="n">opener</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">build_opener</span><span class="p">(</span><span class="n">handler</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># use the opener to fetch a URL</span>
|
||||
<span class="n">opener</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">a_url</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Install the opener.</span>
|
||||
<span class="c1"># Now all calls to urllib.request.urlopen use our opener.</span>
|
||||
<span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">install_opener</span><span class="p">(</span><span class="n">opener</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p>在以上例子中,只向 <code class="docutils literal notranslate"><span class="pre">build_opener</span></code> 给出了 <code class="docutils literal notranslate"><span class="pre">HTTPBasicAuthHandler</span></code> 。默认情况下,opener 会有用于处理常见状况的 handler ——<code class="docutils literal notranslate"><span class="pre">ProxyHandler</span></code> (如果设置代理的话,比如设置了环境变量 <span class="target" id="index-11"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">http_proxy</span></code> ),<code class="docutils literal notranslate"><span class="pre">UnknownHandler</span></code> 、<code class="docutils literal notranslate"><span class="pre">HTTPHandler</span></code> 、 <code class="docutils literal notranslate"><span class="pre">HTTPDefaultErrorHandler</span></code> 、 <code class="docutils literal notranslate"><span class="pre">HTTPRedirectHandler</span></code> 、 <code class="docutils literal notranslate"><span class="pre">FTPHandler</span></code> 、 <code class="docutils literal notranslate"><span class="pre">FileHandler</span></code> 、 <code class="docutils literal notranslate"><span class="pre">DataHandler</span></code> 、 <code class="docutils literal notranslate"><span class="pre">HTTPErrorProcessor</span></code> 。</p>
|
||||
</div>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">top_level_url</span></code> 其实 <em>要么</em> 是一条完整的 URL(包括 “http:” 部分和主机名及可选的端口号),比如 <code class="docutils literal notranslate"><span class="pre">"http://example.com/"</span></code> , <em>要么</em> 是一条“访问权限”(即主机名,及可选的端口号),比如 <code class="docutils literal notranslate"><span class="pre">"example.com"</span></code> 或 <code class="docutils literal notranslate"><span class="pre">"example.com:8080"</span></code> (后一个示例包含了端口号)。访问权限 <strong>不得</strong> 包含“用户信息”部分——比如 <code class="docutils literal notranslate"><span class="pre">"joe:password@example.com"</span></code> 就不正确。</p>
|
||||
</section>
|
||||
<section id="proxies">
|
||||
<h2>代理<a class="headerlink" href="#proxies" title="永久链接至标题">¶</a></h2>
|
||||
<p><strong>urllib</strong> 将自动检测并使用代理设置。 这是通过 <code class="docutils literal notranslate"><span class="pre">ProxyHandler</span></code> 实现的,当检测到代理设置时,是正常 handler 链中的一部分。通常这是一件好事,但有时也可能会无效 <a class="footnote-reference brackets" href="#id12" id="id6">5</a>。 一种方案是配置自己的 <code class="docutils literal notranslate"><span class="pre">ProxyHandler</span></code> ,不要定义代理。 设置的步骤与 <a class="reference internal" href="#basic-authentication">Basic Authentication</a> handler 类似:</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">proxy_support</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">ProxyHandler</span><span class="p">({})</span>
|
||||
<span class="gp">>>> </span><span class="n">opener</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">build_opener</span><span class="p">(</span><span class="n">proxy_support</span><span class="p">)</span>
|
||||
<span class="gp">>>> </span><span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">install_opener</span><span class="p">(</span><span class="n">opener</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p>目前 <code class="docutils literal notranslate"><span class="pre">urllib.request</span></code> <em>尚不</em> 支持通过代理抓取 <code class="docutils literal notranslate"><span class="pre">https</span></code> 链接地址。 但此功能可以通过扩展 urllib.request 来启用,如以下例程所示 <a class="footnote-reference brackets" href="#id13" id="id7">6</a>。</p>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">注解</p>
|
||||
<p>如果设置了 <code class="docutils literal notranslate"><span class="pre">REQUEST_METHOD</span></code> 变量,则会忽略 <code class="docutils literal notranslate"><span class="pre">HTTP_PROXY</span></code> ;参阅 <a class="reference internal" href="../library/urllib.request.html#urllib.request.getproxies" title="urllib.request.getproxies"><code class="xref py py-func docutils literal notranslate"><span class="pre">getproxies()</span></code></a> 文档。</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="sockets-and-layers">
|
||||
<h2>套接字与分层<a class="headerlink" href="#sockets-and-layers" title="永久链接至标题">¶</a></h2>
|
||||
<p>Python 获取 Web 资源的能力是分层的。urllib 用到的是 <a class="reference internal" href="../library/http.client.html#module-http.client" title="http.client: HTTP and HTTPS protocol client (requires sockets)."><code class="xref py py-mod docutils literal notranslate"><span class="pre">http.client</span></code></a> 库,而后者又用到了套接字库。</p>
|
||||
<p>从 Python 2.3 开始,可以指定套接字等待响应的超时时间。这对必须要读到网页数据的应用程序会很有用。默认情况下,套接字模块 <em>不会超时</em> 并且可以挂起。目前,套接字超时机制未暴露给 http.client 或 urllib.request 层使用。不过可以为所有套接字应用设置默认的全局超时。</p>
|
||||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">socket</span>
|
||||
<span class="kn">import</span> <span class="nn">urllib.request</span>
|
||||
|
||||
<span class="c1"># timeout in seconds</span>
|
||||
<span class="n">timeout</span> <span class="o">=</span> <span class="mi">10</span>
|
||||
<span class="n">socket</span><span class="o">.</span><span class="n">setdefaulttimeout</span><span class="p">(</span><span class="n">timeout</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># this call to urllib.request.urlopen now uses the default timeout</span>
|
||||
<span class="c1"># we have set in the socket module</span>
|
||||
<span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="s1">'http://www.voidspace.org.uk'</span><span class="p">)</span>
|
||||
<span class="n">response</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<hr class="docutils" />
|
||||
<section id="footnotes">
|
||||
<h2>备注<a class="headerlink" href="#footnotes" title="永久链接至标题">¶</a></h2>
|
||||
<p>这篇文档由 John Lee 审订。</p>
|
||||
<dl class="footnote brackets">
|
||||
<dt class="label" id="id8"><span class="brackets"><a class="fn-backref" href="#id1">1</a></span></dt>
|
||||
<dd><p>例如 Google。</p>
|
||||
</dd>
|
||||
<dt class="label" id="id9"><span class="brackets"><a class="fn-backref" href="#id2">2</a></span></dt>
|
||||
<dd><p>对于网站设计而言,探测不同的浏览器是非常糟糕的做法——更为明智的做法是采用 web 标准构建网站。不幸的是,很多网站依然向不同的浏览器发送不同版本的网页。</p>
|
||||
</dd>
|
||||
<dt class="label" id="id10"><span class="brackets"><a class="fn-backref" href="#id3">3</a></span></dt>
|
||||
<dd><p>MSIE 6 的 user-agent 信息是 <em>“Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)”</em></p>
|
||||
</dd>
|
||||
<dt class="label" id="id11"><span class="brackets"><a class="fn-backref" href="#id4">4</a></span></dt>
|
||||
<dd><p>有关 HTTP 请求的头部信息,详情请参阅 <a class="reference internal" href="#quick-reference-to-http-headers">Quick Reference to HTTP Headers</a>。</p>
|
||||
</dd>
|
||||
<dt class="label" id="id12"><span class="brackets"><a class="fn-backref" href="#id6">5</a></span></dt>
|
||||
<dd><p>本人必须使用代理才能在工作中访问互联网。如果尝试通过代理获取 <em>localhost</em> URL,将会遭到阻止。IE 设置为代理模式,urllib 就会获取到配置信息。为了用 localhost 服务器测试脚本,我必须阻止 urllib 使用代理。</p>
|
||||
</dd>
|
||||
<dt class="label" id="id13"><span class="brackets"><a class="fn-backref" href="#id7">6</a></span></dt>
|
||||
<dd><p>urllib 的 SSL 代理 opener(CONNECT 方法): <a class="reference external" href="https://code.activestate.com/recipes/456195/">ASPN Cookbook Recipe</a> 。</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</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="#">如何利用 urllib 包获取网络资源</a><ul>
|
||||
<li><a class="reference internal" href="#introduction">概述</a></li>
|
||||
<li><a class="reference internal" href="#fetching-urls">获取 URL 资源</a><ul>
|
||||
<li><a class="reference internal" href="#data">数据</a></li>
|
||||
<li><a class="reference internal" href="#headers">HTTP 头部信息</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#handling-exceptions">异常的处理</a><ul>
|
||||
<li><a class="reference internal" href="#urlerror">URLError</a></li>
|
||||
<li><a class="reference internal" href="#httperror">HTTPError</a><ul>
|
||||
<li><a class="reference internal" href="#error-codes">错误代码</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#wrapping-it-up">总之</a><ul>
|
||||
<li><a class="reference internal" href="#number-1">第一种方案</a></li>
|
||||
<li><a class="reference internal" href="#number-2">第二种方案</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#info-and-geturl">info 和 geturl 方法</a></li>
|
||||
<li><a class="reference internal" href="#openers-and-handlers">Opener 和 Handler</a></li>
|
||||
<li><a class="reference internal" href="#id5">基本认证</a></li>
|
||||
<li><a class="reference internal" href="#proxies">代理</a></li>
|
||||
<li><a class="reference internal" href="#sockets-and-layers">套接字与分层</a></li>
|
||||
<li><a class="reference internal" href="#footnotes">备注</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>上一个主题</h4>
|
||||
<p class="topless"><a href="unicode.html"
|
||||
title="上一章">Unicode 指南</a></p>
|
||||
<h4>下一个主题</h4>
|
||||
<p class="topless"><a href="argparse.html"
|
||||
title="下一章">argparse 教程</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/howto/urllib2.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="argparse.html" title="argparse 教程"
|
||||
>下一页</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="unicode.html" title="Unicode 指南"
|
||||
>上一页</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> »</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> »
|
||||
</li>
|
||||
|
||||
<li class="nav-item nav-item-1"><a href="index.html" >Python 指南</a> »</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">
|
||||
© <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>
|
||||
Reference in New Issue
Block a user