685 lines
88 KiB
HTML
685 lines
88 KiB
HTML
|
||
<!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="stable.html" />
|
||
<link rel="prev" title="Python/C API 参考手册" href="index.html" />
|
||
<link rel="canonical" href="https://docs.python.org/3/c-api/intro.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="#coding-standards">代码标准</a></li>
|
||
<li><a class="reference internal" href="#include-files">包含文件</a></li>
|
||
<li><a class="reference internal" href="#useful-macros">有用的宏</a></li>
|
||
<li><a class="reference internal" href="#objects-types-and-reference-counts">对象、类型和引用计数</a><ul>
|
||
<li><a class="reference internal" href="#reference-counts">引用计数</a><ul>
|
||
<li><a class="reference internal" href="#reference-count-details">引用计数细节</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#types">类型</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#exceptions">异常</a></li>
|
||
<li><a class="reference internal" href="#embedding-python">嵌入Python</a></li>
|
||
<li><a class="reference internal" href="#debugging-builds">调试构建</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>上一个主题</h4>
|
||
<p class="topless"><a href="index.html"
|
||
title="上一章">Python/C API 参考手册</a></p>
|
||
<h4>下一个主题</h4>
|
||
<p class="topless"><a href="stable.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/c-api/intro.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/c-api/intro.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="stable.html" title="稳定的应用程序二进制接口"
|
||
accesskey="N">下一页</a> |</li>
|
||
<li class="right" >
|
||
<a href="index.html" title="Python/C API 参考手册"
|
||
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/C API 参考手册</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="introduction">
|
||
<span id="api-intro"></span><h1>概述<a class="headerlink" href="#introduction" title="永久链接至标题">¶</a></h1>
|
||
<p>Python 的应用编程接口(API)使得 C 和 C++ 程序员可以在多个层级上访问 Python 解释器。该 API 在 C++ 中同样可用,但为简化描述,通常将其称为 Python/C API。使用 Python/C API 有两个基本的理由。第一个理由是为了特定目的而编写 <em>扩展模块</em>;它们是扩展 Python 解释器功能的 C 模块。这可能是最常见的使用场景。第二个理由是将 Python 用作更大规模应用的组件;这种技巧通常被称为在一个应用中 <em class="dfn">embedding</em> Python。</p>
|
||
<p>编写扩展模块的过程相对来说更易于理解,可以通过“菜谱”的形式分步骤介绍。使用某些工具可在一定程度上自动化这一过程。虽然人们在其他应用中嵌入 Python 的做法早已有之,但嵌入 Python 的过程没有编写扩展模块那样方便直观。</p>
|
||
<p>许多 API 函数在你嵌入或是扩展 Python 这两种场景下都能发挥作用;此外,大多数嵌入 Python 的应用程序也需要提供自定义扩展,因此在尝试在实际应用中嵌入 Python 之前先熟悉编写扩展应该会是个好主意。</p>
|
||
<section id="coding-standards">
|
||
<h2>代码标准<a class="headerlink" href="#coding-standards" title="永久链接至标题">¶</a></h2>
|
||
<p>如果你想要编写可包含于 CPython 的 C 代码,你 <strong>必须</strong> 遵循在 <span class="target" id="index-46"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0007"><strong>PEP 7</strong></a> 中定义的指导原则和标准。这些指导原则适用于任何你所要扩展的 Python 版本。在编写你自己的第三方扩展模块时可以不必遵循这些规范,除非你准备在日后向 Python 贡献这些模块。</p>
|
||
</section>
|
||
<section id="include-files">
|
||
<span id="api-includes"></span><h2>包含文件<a class="headerlink" href="#include-files" title="永久链接至标题">¶</a></h2>
|
||
<p>使用 Python/C API 所需要的全部函数、类型和宏定义可通过下面这行语句包含到你的代码之中:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#define PY_SSIZE_T_CLEAN</span>
|
||
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><Python.h></span>
|
||
</pre></div>
|
||
</div>
|
||
<p>这意味着包含以下标准头文件:<code class="docutils literal notranslate"><span class="pre"><stdio.h></span></code>,<code class="docutils literal notranslate"><span class="pre"><string.h></span></code>,<code class="docutils literal notranslate"><span class="pre"><errno.h></span></code>,<code class="docutils literal notranslate"><span class="pre"><limits.h></span></code>,<code class="docutils literal notranslate"><span class="pre"><assert.h></span></code> 和 <code class="docutils literal notranslate"><span class="pre"><stdlib.h></span></code>(如果可用)。</p>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">注解</p>
|
||
<p>由于 Python 可能会定义一些能在某些系统上影响标准头文件的预处理器定义,因此在包含任何标准头文件之前,你 <em>必须</em> 先包含 <code class="file docutils literal notranslate"><span class="pre">Python.h</span></code>。</p>
|
||
<p>推荐总是在 <code class="docutils literal notranslate"><span class="pre">Python.h</span></code> 前定义 <code class="docutils literal notranslate"><span class="pre">PY_SSIZE_T_CLEAN</span></code> 。查看 <a class="reference internal" href="arg.html#arg-parsing"><span class="std std-ref">解析参数并构建值变量</span></a> 来了解这个宏的更多内容。</p>
|
||
</div>
|
||
<p>Python.h 所定义的全部用户可见名称(由包含的标准头文件所定义的除外)都带有前缀 <code class="docutils literal notranslate"><span class="pre">Py</span></code> 或者 <code class="docutils literal notranslate"><span class="pre">_Py</span></code>。以 <code class="docutils literal notranslate"><span class="pre">_Py</span></code> 打头的名称是供 Python 实现内部使用的,不应被扩展编写者使用。结构成员名称没有保留前缀。</p>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">注解</p>
|
||
<p>用户代码永远不应该定义以 <code class="docutils literal notranslate"><span class="pre">Py</span></code> 或 <code class="docutils literal notranslate"><span class="pre">_Py</span></code> 开头的名称。这会使读者感到困惑,并危及用户代码对未来Python版本的可移植性,这些版本可能会定义以这些前缀之一开头的其他名称。</p>
|
||
</div>
|
||
<p>头文件通常会与 Python 一起安装。在 Unix 上,它们位于以下目录:<code class="file docutils literal notranslate"><em><span class="pre">prefix</span></em><span class="pre">/include/pythonversion/</span></code> 和 <code class="file docutils literal notranslate"><em><span class="pre">exec_prefix</span></em><span class="pre">/include/pythonversion/</span></code>,其中 <span class="target" id="index-47"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">prefix</span></code> 和 <span class="target" id="index-48"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">exec_prefix</span></code> 是由向 Python 的 <strong class="program">configure</strong> 脚本传入的对应形参所定义,而 <em>version</em> 则为 <code class="docutils literal notranslate"><span class="pre">'%d.%d'</span> <span class="pre">%</span> <span class="pre">sys.version_info[:2]</span></code>。在 Windows 上,头文件安装于 <code class="file docutils literal notranslate"><em><span class="pre">prefix</span></em><span class="pre">/include</span></code>,其中 <span class="target" id="index-49"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">prefix</span></code> 是向安装程序指定的安装目录。</p>
|
||
<p>要包含头文件,请将两个目录(如果不同)都放到你所用编译器的包含搜索路径中。请 <em>不要</em> 将父目录放入搜索路径然后使用 <code class="docutils literal notranslate"><span class="pre">#include</span> <span class="pre"><pythonX.Y/Python.h></span></code>;这将使得多平台编译不可用,因为 <span class="target" id="index-50"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">prefix</span></code> 下平台无关的头文件需要包含来自 <span class="target" id="index-51"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">exec_prefix</span></code> 下特定平台的头文件。</p>
|
||
<p>C++ 用户应该注意,尽管 API 是完全使用 C 来定义的,但头文件正确地将入口点声明为 <code class="docutils literal notranslate"><span class="pre">extern</span> <span class="pre">"C"</span></code>,因此 API 在 C++ 中使用此 API 不必再做任何特殊处理。</p>
|
||
</section>
|
||
<section id="useful-macros">
|
||
<h2>有用的宏<a class="headerlink" href="#useful-macros" title="永久链接至标题">¶</a></h2>
|
||
<p>Python 头文件中定义了一些有用的宏。许多是在靠近它们被使用的地方定义的(例如 <a class="reference internal" href="none.html#c.Py_RETURN_NONE" title="Py_RETURN_NONE"><code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_RETURN_NONE</span></code></a>)。其他更为通用的则定义在这里。这里所显示的并不是一个完整的列表。</p>
|
||
<dl class="macro">
|
||
<dt id="c.Py_UNREACHABLE">
|
||
<code class="sig-name descname">Py_UNREACHABLE</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#c.Py_UNREACHABLE" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>这个可以在你有一个不打算被触及的代码路径时使用。例如,当一个 <code class="docutils literal notranslate"><span class="pre">switch</span></code> 语句中所有可能的值都已被 <code class="docutils literal notranslate"><span class="pre">case</span></code> 子句覆盖了,就可将其用在 <code class="docutils literal notranslate"><span class="pre">default:</span></code> 子句中。当你非常想在某个位置放一个 <code class="docutils literal notranslate"><span class="pre">assert(0)</span></code> 或 <code class="docutils literal notranslate"><span class="pre">abort()</span></code> 调用时也可以用这个。</p>
|
||
<div class="versionadded">
|
||
<p><span class="versionmodified added">3.7 新版功能.</span></p>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_ABS">
|
||
<code class="sig-name descname">Py_ABS</code><span class="sig-paren">(</span>x<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_ABS" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>返回 <code class="docutils literal notranslate"><span class="pre">x</span></code> 的绝对值。</p>
|
||
<div class="versionadded">
|
||
<p><span class="versionmodified added">3.3 新版功能.</span></p>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_MIN">
|
||
<code class="sig-name descname">Py_MIN</code><span class="sig-paren">(</span>x, y<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_MIN" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>返回 <code class="docutils literal notranslate"><span class="pre">x</span></code> 和 <code class="docutils literal notranslate"><span class="pre">y</span></code> 当中的最小值。</p>
|
||
<div class="versionadded">
|
||
<p><span class="versionmodified added">3.3 新版功能.</span></p>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_MAX">
|
||
<code class="sig-name descname">Py_MAX</code><span class="sig-paren">(</span>x, y<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_MAX" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>返回 <code class="docutils literal notranslate"><span class="pre">x</span></code> 和 <code class="docutils literal notranslate"><span class="pre">y</span></code> 当中的最大值。</p>
|
||
<div class="versionadded">
|
||
<p><span class="versionmodified added">3.3 新版功能.</span></p>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_STRINGIFY">
|
||
<code class="sig-name descname">Py_STRINGIFY</code><span class="sig-paren">(</span>x<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_STRINGIFY" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>将 <code class="docutils literal notranslate"><span class="pre">x</span></code> 转换为 C 字符串。例如 <code class="docutils literal notranslate"><span class="pre">Py_STRINGIFY(123)</span></code> 返回 <code class="docutils literal notranslate"><span class="pre">"123"</span></code>。</p>
|
||
<div class="versionadded">
|
||
<p><span class="versionmodified added">3.4 新版功能.</span></p>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_MEMBER_SIZE">
|
||
<code class="sig-name descname">Py_MEMBER_SIZE</code><span class="sig-paren">(</span>type, member<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_MEMBER_SIZE" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>返回结构 (<code class="docutils literal notranslate"><span class="pre">type</span></code>) <code class="docutils literal notranslate"><span class="pre">member</span></code> 的大小,以字节表示。</p>
|
||
<div class="versionadded">
|
||
<p><span class="versionmodified added">3.6 新版功能.</span></p>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_CHARMASK">
|
||
<code class="sig-name descname">Py_CHARMASK</code><span class="sig-paren">(</span>c<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_CHARMASK" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>参数必须为 [-128, 127] 或 [0, 255] 范围内的字符或整数类型。这个宏将 <code class="docutils literal notranslate"><span class="pre">c</span></code> 强制转换为 <code class="docutils literal notranslate"><span class="pre">unsigned</span> <span class="pre">char</span></code> 返回。</p>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_GETENV">
|
||
<code class="sig-name descname">Py_GETENV</code><span class="sig-paren">(</span>s<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_GETENV" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>与 <code class="docutils literal notranslate"><span class="pre">getenv(s)</span></code> 类似,但是如果命令行上传递了 <a class="reference internal" href="../using/cmdline.html#cmdoption-e"><code class="xref std std-option docutils literal notranslate"><span class="pre">-E</span></code></a> ,则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> (即如果设置了 <code class="docutils literal notranslate"><span class="pre">Py_IgnoreEnvironmentFlag</span></code> )。</p>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_UNUSED">
|
||
<code class="sig-name descname">Py_UNUSED</code><span class="sig-paren">(</span>arg<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_UNUSED" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>用于函数定义中未使用的参数,从而消除编译器警告。例如: <code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">func(int</span> <span class="pre">a,</span> <span class="pre">int</span> <span class="pre">Py_UNUSED(b))</span> <span class="pre">{</span> <span class="pre">return</span> <span class="pre">a;</span> <span class="pre">}</span></code> 。</p>
|
||
<div class="versionadded">
|
||
<p><span class="versionmodified added">3.4 新版功能.</span></p>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.Py_DEPRECATED">
|
||
<code class="sig-name descname">Py_DEPRECATED</code><span class="sig-paren">(</span>version<span class="sig-paren">)</span><a class="headerlink" href="#c.Py_DEPRECATED" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>弃用声明。该宏必须放置在符号名称前。</p>
|
||
<p>示例:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Py_DEPRECATED</span><span class="p">(</span><span class="mf">3.8</span><span class="p">)</span><span class="w"> </span><span class="n">PyAPI_FUNC</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="n">Py_OldFunction</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="versionchanged">
|
||
<p><span class="versionmodified changed">在 3.8 版更改: </span>添加了 MSVC 支持。</p>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.PyDoc_STRVAR">
|
||
<code class="sig-name descname">PyDoc_STRVAR</code><span class="sig-paren">(</span>name, str<span class="sig-paren">)</span><a class="headerlink" href="#c.PyDoc_STRVAR" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>创建一个可以在文档字符串中使用的,名字为 <code class="docutils literal notranslate"><span class="pre">name</span></code> 的变量。如果不和文档字符串一起构建 Python,该值将为空。</p>
|
||
<p>如 <span class="target" id="index-52"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0007"><strong>PEP 7</strong></a> 所述,使用 <a class="reference internal" href="#c.PyDoc_STRVAR" title="PyDoc_STRVAR"><code class="xref c c-macro docutils literal notranslate"><span class="pre">PyDoc_STRVAR</span></code></a> 作为文档字符串,以支持不和文档字符串一起构建 Python 的情况。</p>
|
||
<p>示例:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyDoc_STRVAR</span><span class="p">(</span><span class="n">pop_doc</span><span class="p">,</span><span class="w"> </span><span class="s">"Remove and return the rightmost element."</span><span class="p">);</span>
|
||
|
||
<span class="k">static</span><span class="w"> </span><span class="n">PyMethodDef</span><span class="w"> </span><span class="n">deque_methods</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="c1">// ...</span>
|
||
<span class="w"> </span><span class="p">{</span><span class="s">"pop"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">PyCFunction</span><span class="p">)</span><span class="n">deque_pop</span><span class="p">,</span><span class="w"> </span><span class="n">METH_NOARGS</span><span class="p">,</span><span class="w"> </span><span class="n">pop_doc</span><span class="p">},</span>
|
||
<span class="w"> </span><span class="c1">// ...</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
<dl class="macro">
|
||
<dt id="c.PyDoc_STR">
|
||
<code class="sig-name descname">PyDoc_STR</code><span class="sig-paren">(</span>str<span class="sig-paren">)</span><a class="headerlink" href="#c.PyDoc_STR" title="永久链接至目标">¶</a></dt>
|
||
<dd><p>为给定的字符串输入创建一个文档字符串,或者当文档字符串被禁用时,创建一个空字符串。</p>
|
||
<p>如 <span class="target" id="index-53"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0007"><strong>PEP 7</strong></a> 所述,使用 <a class="reference internal" href="#c.PyDoc_STR" title="PyDoc_STR"><code class="xref c c-macro docutils literal notranslate"><span class="pre">PyDoc_STR</span></code></a> 指定文档字符串,以支持不和文档字符串一起构建 Python 的情况。</p>
|
||
<p>示例:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="n">PyMethodDef</span><span class="w"> </span><span class="n">pysqlite_row_methods</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="p">{</span><span class="s">"keys"</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">PyCFunction</span><span class="p">)</span><span class="n">pysqlite_row_keys</span><span class="p">,</span><span class="w"> </span><span class="n">METH_NOARGS</span><span class="p">,</span>
|
||
<span class="w"> </span><span class="n">PyDoc_STR</span><span class="p">(</span><span class="s">"Returns the keys of the row."</span><span class="p">)},</span>
|
||
<span class="w"> </span><span class="p">{</span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">}</span>
|
||
<span class="p">};</span>
|
||
</pre></div>
|
||
</div>
|
||
</dd></dl>
|
||
|
||
</section>
|
||
<section id="objects-types-and-reference-counts">
|
||
<span id="api-objects"></span><h2>对象、类型和引用计数<a class="headerlink" href="#objects-types-and-reference-counts" title="永久链接至标题">¶</a></h2>
|
||
<p id="index-8">多数 Python/C API 有一个或多个参数,以及一个 <a class="reference internal" href="structures.html#c.PyObject" title="PyObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyObject*</span></code></a> 类型的返回值。这种类型是指向任意 Python 对象的不透明数据类型的指针。所有 Python 对象类型在大多数情况下都被 Python 语言由相同的方式处理(例如,赋值,作用域规则,和参数传递),因此将它们由单个 C 类型表示才合适。几乎所有 Python 对象存放在堆中:你不能声明一个类型为 <a class="reference internal" href="structures.html#c.PyObject" title="PyObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyObject</span></code></a> 的自动或静态的变量,只能声明类型为 <a class="reference internal" href="structures.html#c.PyObject" title="PyObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyObject*</span></code></a> 的指针。type 对象是唯一的例外,因为它们永远不能被释放,所以它们通常是静态的 <a class="reference internal" href="type.html#c.PyTypeObject" title="PyTypeObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyTypeObject</span></code></a> 对象。</p>
|
||
<p>所有 Python 对象(甚至 Python 整数)都有一个 <em class="dfn">type</em> 和一个 <em class="dfn">reference count</em>。对象的类型确定它是什么类型的对象(例如整数、列表或用户定义函数;还有更多,如 <a class="reference internal" href="../reference/datamodel.html#types"><span class="std std-ref">标准类型层级结构</span></a> 中所述)。对于每个众所周知的类型,都有一个宏来检查对象是否属于该类型;例如,当(且仅当) <em>a</em> 所指的对象是 Python 列表时 <code class="docutils literal notranslate"><span class="pre">PyList_Check(a)</span></code> 为真。</p>
|
||
<section id="reference-counts">
|
||
<span id="api-refcounts"></span><h3>引用计数<a class="headerlink" href="#reference-counts" title="永久链接至标题">¶</a></h3>
|
||
<p>引用计数非常重要,因为现代计算机内存(通常十分)有限;它计算有多少不同的地方引用同一个对象。这样的地方可以是某个对象,或者是某个全局(或静态)C 变量,亦或是某个 C 函数的局部变量。当一个对象的引用计数变为 0,释放该对象。如果这个已释放的对象包含其它对象的引用计数,则递减这些对象的引用计数。如果这些对象的引用计数减少为零,则可以依次释放这些对象,依此类推。(这里有一个很明显的问题——对象之间相互引用;目前,解决方案是“不要那样做”。)</p>
|
||
<p id="index-9">总是显式操作引用计数。通常的方法是使用宏 <a class="reference internal" href="refcounting.html#c.Py_INCREF" title="Py_INCREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_INCREF()</span></code></a> 来增加一个对象的引用计数,使用宏 <a class="reference internal" href="refcounting.html#c.Py_DECREF" title="Py_DECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_DECREF()</span></code></a> 来减少一个对象的引用计数。宏 <a class="reference internal" href="refcounting.html#c.Py_DECREF" title="Py_DECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_DECREF()</span></code></a> 必须检查引用计数是否为零,然后调用对象的释放器, 因此它比 incref 宏复杂得多。释放器是一个包含在对象类型结构中的函数指针。如果对象是复合对象类型(例如列表),则类型特定的释放器负责递减包含在对象中的其他对象的引用计数,并执行所需的终结。引用计数不会溢出,至少用与虚拟内存中不同内存位置一样多的位用于保存引用计数(即 <code class="docutils literal notranslate"><span class="pre">sizeof(Py_ssize_t)</span> <span class="pre">>=</span> <span class="pre">sizeof(void*)</span></code> )。因此,引用计数递增是一个简单的操作。</p>
|
||
<p>没有必要为每个包含指向对象的指针的局部变量增加对象的引用计数。理论上,当变量指向对象时,对象的引用计数增加 1 ,当变量超出范围时,对象的引用计数减少 1 。但是,这两者相互抵消,所以最后引用计数没有改变。使用引用计数的唯一真正原因是只要我们的变量指向它,就可以防止对象被释放。如果知道至少有一个对该对象的其他引用存活时间至少和我们的变量一样长,则没必要临时增加引用计数。一个典型的情形是,对象作为参数从 Python 中传递给被调用的扩展模块中的 C 函数时,调用机制会保证在调用期间持有对所有参数的引用。</p>
|
||
<p>但是,有一个常见的陷阱是从列表中提取一个对象,并将其持有一段时间,而不增加其引用计数。某些操作可能会从列表中删除某个对象,减少其引用计数,并有可能重新分配这个对象。真正的危险是,这个看似无害的操作可能会调用任意 Python 代码——也许有一个代码路径允许控制流从 <a class="reference internal" href="refcounting.html#c.Py_DECREF" title="Py_DECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_DECREF()</span></code></a> 回到用户,因此在复合对象上的操作都存在潜在的风险。</p>
|
||
<p>一个安全的方式是始终使用泛型操作(名称以 <code class="docutils literal notranslate"><span class="pre">PyObject_</span></code> , <code class="docutils literal notranslate"><span class="pre">PyNumber_</span></code> , <code class="docutils literal notranslate"><span class="pre">PySequence_</span></code> 或 <code class="docutils literal notranslate"><span class="pre">PyMapping_</span></code> 开头的函数)。这些操作总是增加它们返回的对象的引用计数。这让调用者有责任在获得结果后调用 <a class="reference internal" href="refcounting.html#c.Py_DECREF" title="Py_DECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_DECREF()</span></code></a> 。习惯这种方式很简单。</p>
|
||
<section id="reference-count-details">
|
||
<span id="api-refcountdetails"></span><h4>引用计数细节<a class="headerlink" href="#reference-count-details" title="永久链接至标题">¶</a></h4>
|
||
<p>The reference count behavior of functions in the Python/C API is best explained
|
||
in terms of <em>ownership of references</em>. Ownership pertains to references, never
|
||
to objects (objects are not owned: they are always shared). "Owning a
|
||
reference" means being responsible for calling Py_DECREF on it when the
|
||
reference is no longer needed. Ownership can also be transferred, meaning that
|
||
the code that receives ownership of the reference then becomes responsible for
|
||
eventually decref'ing it by calling <a class="reference internal" href="refcounting.html#c.Py_DECREF" title="Py_DECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_DECREF()</span></code></a> or <a class="reference internal" href="refcounting.html#c.Py_XDECREF" title="Py_XDECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_XDECREF()</span></code></a>
|
||
when it's no longer needed---or passing on this responsibility (usually to its
|
||
caller). When a function passes ownership of a reference on to its caller, the
|
||
caller is said to receive a <em>new</em> reference. When no ownership is transferred,
|
||
the caller is said to <em>borrow</em> the reference. Nothing needs to be done for a
|
||
borrowed reference.</p>
|
||
<p>相反地,当调用方函数传入一个对象的引用时,存在两种可能:该函数 <em>窃取</em> 了一个对象的引用,或是没有窃取。 <em>窃取引用</em> 意味着当你向一个函数传入引用时,该函数会假定它拥有该引用,而你将不再对它负有责任。</p>
|
||
<p id="index-10">很少有函数会窃取引用;两个重要的例外是 <a class="reference internal" href="list.html#c.PyList_SetItem" title="PyList_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyList_SetItem()</span></code></a> 和 <a class="reference internal" href="tuple.html#c.PyTuple_SetItem" title="PyTuple_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyTuple_SetItem()</span></code></a>,它们会窃取对条目的引用(但不是条目所在的元组或列表!)。 这些函数被设计为会窃取引用是因为在使用新创建的对象来填充元组或列表时有一个通常的惯例;例如,创建元组 <code class="docutils literal notranslate"><span class="pre">(1,</span> <span class="pre">2,</span> <span class="pre">"three")</span></code> 的代码看起来可以是这样的(暂时不要管错误处理;下面会显示更好的代码编写方式):</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">t</span><span class="p">;</span>
|
||
|
||
<span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyTuple_New</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
|
||
<span class="n">PyTuple_SetItem</span><span class="p">(</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">PyLong_FromLong</span><span class="p">(</span><span class="mf">1L</span><span class="p">));</span>
|
||
<span class="n">PyTuple_SetItem</span><span class="p">(</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">PyLong_FromLong</span><span class="p">(</span><span class="mf">2L</span><span class="p">));</span>
|
||
<span class="n">PyTuple_SetItem</span><span class="p">(</span><span class="n">t</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">"three"</span><span class="p">));</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>在这里,<a class="reference internal" href="long.html#c.PyLong_FromLong" title="PyLong_FromLong"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_FromLong()</span></code></a> 返回了一个新的引用并且它立即被 <a class="reference internal" href="tuple.html#c.PyTuple_SetItem" title="PyTuple_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyTuple_SetItem()</span></code></a> 所窃取。 当你想要继续使用一个对象而对它的引用将被窃取时,请在调用窃取引用的函数之前使用 <a class="reference internal" href="refcounting.html#c.Py_INCREF" title="Py_INCREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_INCREF()</span></code></a> 来抓取另一个引用。</p>
|
||
<p>顺便提一下,<a class="reference internal" href="tuple.html#c.PyTuple_SetItem" title="PyTuple_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyTuple_SetItem()</span></code></a> 是设置元组条目的 <em>唯一</em> 方式;<a class="reference internal" href="sequence.html#c.PySequence_SetItem" title="PySequence_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PySequence_SetItem()</span></code></a> 和 <a class="reference internal" href="object.html#c.PyObject_SetItem" title="PyObject_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_SetItem()</span></code></a> 会拒绝这样做因为元组是不可变数据类型。 你应当只对你自己创建的元组使用 <a class="reference internal" href="tuple.html#c.PyTuple_SetItem" title="PyTuple_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyTuple_SetItem()</span></code></a>。</p>
|
||
<p>等价于填充一个列表的代码可以使用 <a class="reference internal" href="list.html#c.PyList_New" title="PyList_New"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyList_New()</span></code></a> 和 <a class="reference internal" href="list.html#c.PyList_SetItem" title="PyList_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyList_SetItem()</span></code></a> 来编写。</p>
|
||
<p>然而,在实践中,你很少会使用这些创建和填充元组或列表的方式。 有一个通用的函数 <a class="reference internal" href="arg.html#c.Py_BuildValue" title="Py_BuildValue"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_BuildValue()</span></code></a> 可以根据 C 值来创建大多数常用对象,由一个 <em class="dfn">格式字符串</em> 来指明。 例如,上面的两个代码块可以用下面的代码来代替(还会负责错误检测):</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">tuple</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">list</span><span class="p">;</span>
|
||
|
||
<span class="n">tuple</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Py_BuildValue</span><span class="p">(</span><span class="s">"(iis)"</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="s">"three"</span><span class="p">);</span>
|
||
<span class="n">list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Py_BuildValue</span><span class="p">(</span><span class="s">"[iis]"</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="s">"three"</span><span class="p">);</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>使用 <a class="reference internal" href="object.html#c.PyObject_SetItem" title="PyObject_SetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_SetItem()</span></code></a> 等来处理那些你只是借入引用的条目是更为常见的,例如传给你正在编写的函数的参数。 在这种情况下,他们对于引用计数的行为会更为理智,因为你不需要递增引用计数以便你可以将引用计数转出去(“让它被窃取”)。 例如,这个函数将一个列表(实例上是任何可变序列)中的所有项设置为一个给定的条目:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span>
|
||
<span class="nf">set_all</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">target</span><span class="p">,</span><span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">item</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">;</span>
|
||
|
||
<span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_Length</span><span class="p">(</span><span class="n">target</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">n</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">n</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">index</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLong_FromSsize_t</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">index</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">PyObject_SetItem</span><span class="p">(</span><span class="n">target</span><span class="p">,</span><span class="w"> </span><span class="n">index</span><span class="p">,</span><span class="w"> </span><span class="n">item</span><span class="p">)</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">index</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="p">}</span>
|
||
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">index</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="p">}</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p id="index-11">对于函数返回值的情况略有不同。 虽然向大多数函数传递一个引用不会改变你对该引用的所有权责任,但许多返回一个引用的函数会给你该引用的所有权。 原因很简单:在许多情况下,返回的对象是临时创建的,而你得到的引用是对该对象的唯一引用。 因此,返回对象引用的通用函数,如 <a class="reference internal" href="object.html#c.PyObject_GetItem" title="PyObject_GetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_GetItem()</span></code></a> 和 <a class="reference internal" href="sequence.html#c.PySequence_GetItem" title="PySequence_GetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PySequence_GetItem()</span></code></a>,将总是返回一个新的引用(调用方将成为该引用的所有者)。</p>
|
||
<p>一个需要了解的重点在于你是否拥有一个由函数返回的引用只取决于你所调用的函数 --- <em>附带物</em> (作为参数传给函数的对象的类型) <em>不会带来额外影响!</em> 因此,如果你使用 <a class="reference internal" href="list.html#c.PyList_GetItem" title="PyList_GetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyList_GetItem()</span></code></a> 从一个列表提取条目,你并不会拥有其引用 --- 但是如果你使用 <a class="reference internal" href="sequence.html#c.PySequence_GetItem" title="PySequence_GetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PySequence_GetItem()</span></code></a> (它恰好接受完全相同的参数) 从同一个列表获取同样的条目,你就会拥有一个对所返回对象的引用。</p>
|
||
<p id="index-12">下面是说明你要如何编写一个函数来计算一个整数列表中条目的示例;一个是使用 <a class="reference internal" href="list.html#c.PyList_GetItem" title="PyList_GetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyList_GetItem()</span></code></a>,而另一个是使用 <a class="reference internal" href="sequence.html#c.PySequence_GetItem" title="PySequence_GetItem"><code class="xref c c-func docutils literal notranslate"><span class="pre">PySequence_GetItem()</span></code></a>。</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">long</span>
|
||
<span class="nf">sum_list</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">list</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">total</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">item</span><span class="p">;</span>
|
||
|
||
<span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyList_Size</span><span class="p">(</span><span class="n">list</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">n</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Not a list */</span>
|
||
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">n</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyList_GetItem</span><span class="p">(</span><span class="n">list</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">);</span><span class="w"> </span><span class="cm">/* Can't fail */</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">PyLong_Check</span><span class="p">(</span><span class="n">item</span><span class="p">))</span><span class="w"> </span><span class="k">continue</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Skip non-integers */</span>
|
||
<span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLong_AsLong</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">value</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">-1</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">PyErr_Occurred</span><span class="p">())</span>
|
||
<span class="w"> </span><span class="cm">/* Integer too big to fit in a C long, bail out */</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="n">total</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="p">}</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">total</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-c notranslate" id="index-13"><div class="highlight"><pre><span></span><span class="kt">long</span>
|
||
<span class="nf">sum_sequence</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">sequence</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">total</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">item</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PySequence_Length</span><span class="p">(</span><span class="n">sequence</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">n</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Has no length */</span>
|
||
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">n</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PySequence_GetItem</span><span class="p">(</span><span class="n">sequence</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">item</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Not a sequence, or other failure */</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">PyLong_Check</span><span class="p">(</span><span class="n">item</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLong_AsLong</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">value</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">-1</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">PyErr_Occurred</span><span class="p">())</span>
|
||
<span class="w"> </span><span class="cm">/* Integer too big to fit in a C long, bail out */</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="n">total</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="p">}</span>
|
||
<span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">item</span><span class="p">);</span><span class="w"> </span><span class="cm">/* Discard reference ownership */</span>
|
||
<span class="w"> </span><span class="p">}</span>
|
||
<span class="w"> </span><span class="p">}</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">total</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="types">
|
||
<span id="api-types"></span><span id="index-14"></span><h3>类型<a class="headerlink" href="#types" title="永久链接至标题">¶</a></h3>
|
||
<p>在 Python/C API 中扮演重要角色的其他数据类型很少;大多为简单 C 类型如 <code class="xref c c-type docutils literal notranslate"><span class="pre">int</span></code>, <code class="xref c c-type docutils literal notranslate"><span class="pre">long</span></code>, <code class="xref c c-type docutils literal notranslate"><span class="pre">double</span></code> 和 <code class="xref c c-type docutils literal notranslate"><span class="pre">char*</span></code>。 有一些结构类型被用来描述用于列出模块导出的函数或者某个新对象类型的静态表,还有一个结构类型被用来描述复数的值。 这些结构类型将与使用它们的函数一起讨论。</p>
|
||
</section>
|
||
</section>
|
||
<section id="exceptions">
|
||
<span id="api-exceptions"></span><h2>异常<a class="headerlink" href="#exceptions" title="永久链接至标题">¶</a></h2>
|
||
<p>Python程序员只需要处理特定需要处理的错误异常;未处理的异常会自动传递给调用者,然后传递给调用者的调用者,依此类推,直到他们到达顶级解释器,在那里将它们报告给用户并伴随堆栈回溯。</p>
|
||
<p id="index-15">然而,对于 C 程序员来说,错误检查必须总是显式进行的。 Python/C API 中的所有函数都可以引发异常,除非在函数的文档中另外显式声明。 一般来说,当一个函数遇到错误时,它会设置一个异常,丢弃它所拥有的任何对象引用,并返回一个错误标示。 如果没有说明例外的文档,这个标示将为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 或 <code class="docutils literal notranslate"><span class="pre">-1</span></code>,具体取决于函数的返回类型。 有少量函数会返回一个布尔真/假结果值,其中假值表示错误。 有极少的函数没有显式的错误标示或是具有不明确的返回值,并需要用 <a class="reference internal" href="exceptions.html#c.PyErr_Occurred" title="PyErr_Occurred"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyErr_Occurred()</span></code></a> 来进行显式的检测。 这些例外总是会被明确地记入文档中。</p>
|
||
<p id="index-16">异常状态是在各个线程的存储中维护的(这相当于在一个无线程的应用中使用全局存储)。 一个线程可以处在两种状态之一:异常已经发生,或者没有发生。 函数 <a class="reference internal" href="exceptions.html#c.PyErr_Occurred" title="PyErr_Occurred"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyErr_Occurred()</span></code></a> 可以被用来检查此状态:当异常发生时它将返回一个借入的异常类型对象的引用,在其他情况下则返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>。 有多个函数可以设置异常状态: <a class="reference internal" href="exceptions.html#c.PyErr_SetString" title="PyErr_SetString"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyErr_SetString()</span></code></a> 是最常见的(尽管不是最通用的)设置异常状态的函数,而 <a class="reference internal" href="exceptions.html#c.PyErr_Clear" title="PyErr_Clear"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyErr_Clear()</span></code></a> 可以清除异常状态。</p>
|
||
<p>完整的异常状态由三个对象组成 (它为都可以为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>): 异常类型、相应的异常值,以及回溯信息。 这些对象的含义与 Python 中 <code class="docutils literal notranslate"><span class="pre">sys.exc_info()</span></code> 的结果相同;然而,它们并不是一样的:Python 对象代表由 Python <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> 语句所处理的最后一个异常,而 C 层级的异常状态只在异常被传入到 C 函数或在它们之间传递时存在直至其到达 Python 字节码解释器的主事件循环,该事件循环会负责将其转移至 <code class="docutils literal notranslate"><span class="pre">sys.exc_info()</span></code> 等处。</p>
|
||
<p id="index-17">请注意自 Python 1.5 开始,从 Python 代码访问异常状态的首选的、线程安全的方式是调用函数 <a class="reference internal" href="../library/sys.html#sys.exc_info" title="sys.exc_info"><code class="xref py py-func docutils literal notranslate"><span class="pre">sys.exc_info()</span></code></a>,它将返回 Python 代码的分线程异常状态。 此外,这两种访问异常状态的方式的语义都发生了变化因而捕获到异常的函数将保存并恢复其线程的异常状态以保留其调用方的异常状态。 这将防止异常处理代码中由一个看起来很无辜的函数覆盖了正在处理的异常所造成的常见错误;它还减少了在回溯由栈帧所引用的对象的往往不被需要的生命其延长。</p>
|
||
<p>作为一般的原则,一个调用另一个函数来执行某些任务的函数应当检查被调用的函数是否引发了异常,并在引发异常时将异常状态传递给其调用方。 它应当丢弃它所拥有的任何对象引用,并返回一个错误标示,但它 <em>不应</em> 设置另一个异常 --- 那会覆盖刚引发的异常,并丢失有关错误确切原因的重要信息。</p>
|
||
<p id="index-18">一个检测异常并传递它们的简单例子在上面的 <code class="xref c c-func docutils literal notranslate"><span class="pre">sum_sequence()</span></code> 示例中进行了演示。 这个例子恰好在检测到错误时不需要清理所拥有的任何引用。 下面的示例函数演示了一些错误清理操作。 首先,为了向你提示 Python 的优势,我们展示了等效的 Python 代码:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">def</span><span class="w"> </span><span class="n">incr_item</span><span class="p">(</span><span class="n">dict</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="p">)</span><span class="o">:</span>
|
||
<span class="w"> </span><span class="nl">try</span><span class="p">:</span>
|
||
<span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
|
||
<span class="w"> </span><span class="n">except</span><span class="w"> </span><span class="n">KeyError</span><span class="o">:</span>
|
||
<span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span>
|
||
<span class="w"> </span><span class="n">dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span>
|
||
</pre></div>
|
||
</div>
|
||
<p id="index-19">下面是对应的闪耀荣光的 C 代码:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span>
|
||
<span class="nf">incr_item</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">dict</span><span class="p">,</span><span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">key</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="w"> </span><span class="cm">/* Objects all initialized to NULL for Py_XDECREF */</span>
|
||
<span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">const_one</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">incremented_item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Return value initialized to -1 (failure) */</span>
|
||
|
||
<span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_GetItem</span><span class="p">(</span><span class="n">dict</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">item</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||
<span class="w"> </span><span class="cm">/* Handle KeyError only: */</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">PyErr_ExceptionMatches</span><span class="p">(</span><span class="n">PyExc_KeyError</span><span class="p">))</span>
|
||
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">error</span><span class="p">;</span>
|
||
|
||
<span class="w"> </span><span class="cm">/* Clear the error and use zero: */</span>
|
||
<span class="w"> </span><span class="n">PyErr_Clear</span><span class="p">();</span>
|
||
<span class="w"> </span><span class="n">item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLong_FromLong</span><span class="p">(</span><span class="mf">0L</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">item</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">error</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="p">}</span>
|
||
<span class="w"> </span><span class="n">const_one</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLong_FromLong</span><span class="p">(</span><span class="mf">1L</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">const_one</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">error</span><span class="p">;</span>
|
||
|
||
<span class="w"> </span><span class="n">incremented_item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyNumber_Add</span><span class="p">(</span><span class="n">item</span><span class="p">,</span><span class="w"> </span><span class="n">const_one</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">incremented_item</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">error</span><span class="p">;</span>
|
||
|
||
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">PyObject_SetItem</span><span class="p">(</span><span class="n">dict</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">incremented_item</span><span class="p">)</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
|
||
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">error</span><span class="p">;</span>
|
||
<span class="w"> </span><span class="n">rv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Success */</span>
|
||
<span class="w"> </span><span class="cm">/* Continue with cleanup code */</span>
|
||
|
||
<span class="w"> </span><span class="nl">error</span><span class="p">:</span>
|
||
<span class="w"> </span><span class="cm">/* Cleanup code, shared by success and failure path */</span>
|
||
|
||
<span class="w"> </span><span class="cm">/* Use Py_XDECREF() to ignore NULL references */</span>
|
||
<span class="w"> </span><span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">const_one</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">incremented_item</span><span class="p">);</span>
|
||
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">rv</span><span class="p">;</span><span class="w"> </span><span class="cm">/* -1 for error, 0 for success */</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<span class="target" id="index-20"></span><p id="index-21">这个例子代表了 C 语言中 <code class="docutils literal notranslate"><span class="pre">goto</span></code> 语句一种受到认可的用法! 它说明了如何使用 <a class="reference internal" href="exceptions.html#c.PyErr_ExceptionMatches" title="PyErr_ExceptionMatches"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyErr_ExceptionMatches()</span></code></a> 和 <a class="reference internal" href="exceptions.html#c.PyErr_Clear" title="PyErr_Clear"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyErr_Clear()</span></code></a> 来处理特定的异常,以及如何使用 <a class="reference internal" href="refcounting.html#c.Py_XDECREF" title="Py_XDECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_XDECREF()</span></code></a> 来处理可能为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 的自有引用(注意名称中的 <code class="docutils literal notranslate"><span class="pre">'X'</span></code>;<a class="reference internal" href="refcounting.html#c.Py_DECREF" title="Py_DECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_DECREF()</span></code></a> 在遇到 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 引用时将会崩溃)。 重要的一点在于用来保存自有引用的变量要被初始化为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 才能发挥作用;类似地,建议的返回值也要被初始化为 <code class="docutils literal notranslate"><span class="pre">-1</span></code> (失败) 并且只有在最终执行的调用成功后才会被设置为成功。</p>
|
||
</section>
|
||
<section id="embedding-python">
|
||
<span id="api-embedding"></span><h2>嵌入Python<a class="headerlink" href="#embedding-python" title="永久链接至标题">¶</a></h2>
|
||
<p>只有 Python 解释器的嵌入方(相对于扩展编写者而言)才需要担心的一项重要任务是它的初始化,可能还有它的最终化。 解释器的大多数功能只有在解释器被初始化之后才能被使用。</p>
|
||
<p id="index-22">基本的初始化函数是 <a class="reference internal" href="init.html#c.Py_Initialize" title="Py_Initialize"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_Initialize()</span></code></a>。 此函数将初始化已加载模块表,并创建基本模块 <a class="reference internal" href="../library/builtins.html#module-builtins" title="builtins: The module that provides the built-in namespace."><code class="xref py py-mod docutils literal notranslate"><span class="pre">builtins</span></code></a>, <a class="reference internal" href="../library/__main__.html#module-__main__" title="__main__: The environment where the top-level script is run."><code class="xref py py-mod docutils literal notranslate"><span class="pre">__main__</span></code></a> 和 <a class="reference internal" href="../library/sys.html#module-sys" title="sys: Access system-specific parameters and functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">sys</span></code></a>。 它还将初始化模块搜索路径 (<code class="docutils literal notranslate"><span class="pre">sys.path</span></code>)。</p>
|
||
<p id="index-23"><a class="reference internal" href="init.html#c.Py_Initialize" title="Py_Initialize"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_Initialize()</span></code></a> 不会设置 "脚本参数列表" (<code class="docutils literal notranslate"><span class="pre">sys.argv</span></code>)。 如果随后将要执行的 Python 代码需要此变量,则必须在调用 <a class="reference internal" href="init.html#c.Py_Initialize" title="Py_Initialize"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_Initialize()</span></code></a> 之后通过调用 <code class="docutils literal notranslate"><span class="pre">PySys_SetArgvEx(argc,</span> <span class="pre">argv,</span> <span class="pre">updatepath)</span></code> 来显式地设置它。</p>
|
||
<p>在大多数系统上(特别是 Unix 和 Windows,虽然在细节上有所不同),<a class="reference internal" href="init.html#c.Py_Initialize" title="Py_Initialize"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_Initialize()</span></code></a> 将根据对标准 Python 解释器可执行文件的位置的最佳猜测来计算模块搜索路径,并设定 Python 库可在相对于 Python 解释器可执行文件的固定位置上找到。 特别地,它将相对于在 shell 命令搜索路径 (环境变量 <span class="target" id="index-54"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PATH</span></code>) 上找到的名为 <code class="file docutils literal notranslate"><span class="pre">python</span></code> 的可执行文件所在父目录中查找名为 <code class="file docutils literal notranslate"><span class="pre">lib/python</span><em><span class="pre">X.Y</span></em></code> 的目录。</p>
|
||
<p>举例来说,如果 Python 可执行文件位于 <code class="file docutils literal notranslate"><span class="pre">/usr/local/bin/python</span></code>,它将假定库位于 <code class="file docutils literal notranslate"><span class="pre">/usr/local/lib/python</span><em><span class="pre">X.Y</span></em></code>。 (实际上,这个特定路径还将成为“回退”位置,会在当无法在 <span class="target" id="index-55"></span><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PATH</span></code> 中找到名为 <code class="file docutils literal notranslate"><span class="pre">python</span></code> 的可执行文件时被使用。) 用户可以通过设置环境变量 <span class="target" id="index-56"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONHOME"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONHOME</span></code></a>,或通过设置 <span class="target" id="index-57"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONPATH"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONPATH</span></code></a> 在标准路径之前插入额外的目录来覆盖此行为。</p>
|
||
<p id="index-28">嵌入的应用程序可以通过在调用 <a class="reference internal" href="init.html#c.Py_Initialize" title="Py_Initialize"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_Initialize()</span></code></a> <em>之前</em> 调用 <code class="docutils literal notranslate"><span class="pre">Py_SetProgramName(file)</span></code> 来改变搜索次序。 请注意 <span class="target" id="index-58"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONHOME"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONHOME</span></code></a> 仍然会覆盖此设置并且 <span class="target" id="index-59"></span><a class="reference internal" href="../using/cmdline.html#envvar-PYTHONPATH"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">PYTHONPATH</span></code></a> 仍然会被插入到标准路径之前。 需要完全控制权的应用程序必须提供它自己的 <a class="reference internal" href="init.html#c.Py_GetPath" title="Py_GetPath"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_GetPath()</span></code></a>, <a class="reference internal" href="init.html#c.Py_GetPrefix" title="Py_GetPrefix"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_GetPrefix()</span></code></a>, <a class="reference internal" href="init.html#c.Py_GetExecPrefix" title="Py_GetExecPrefix"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_GetExecPrefix()</span></code></a> 和 <a class="reference internal" href="init.html#c.Py_GetProgramFullPath" title="Py_GetProgramFullPath"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_GetProgramFullPath()</span></code></a> 实现(这些函数均在 <code class="file docutils literal notranslate"><span class="pre">Modules/getpath.c</span></code> 中定义)。</p>
|
||
<p id="index-31">有时,还需要对 Python 进行“反初始化”。 例如,应用程序可能想要重新启动 (再次调用 <a class="reference internal" href="init.html#c.Py_Initialize" title="Py_Initialize"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_Initialize()</span></code></a>) 或者应用程序对 Python 的使用已经完成并想要释放 Python 所分配的内存。 这可以通过调用 <a class="reference internal" href="init.html#c.Py_FinalizeEx" title="Py_FinalizeEx"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_FinalizeEx()</span></code></a> 来实现。 如果当前 Python 处于已初始化状态则 <a class="reference internal" href="init.html#c.Py_IsInitialized" title="Py_IsInitialized"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_IsInitialized()</span></code></a> 函数将返回真值。 有关这些函数的更多信息将在之后的章节中给出。 请注意 <a class="reference internal" href="init.html#c.Py_FinalizeEx" title="Py_FinalizeEx"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_FinalizeEx()</span></code></a> <em>不会</em> 释放所有由 Python 解释器所分配的内存,例如由扩展模块所分配的内存目前是不会被释放的。</p>
|
||
</section>
|
||
<section id="debugging-builds">
|
||
<span id="api-debugging"></span><h2>调试构建<a class="headerlink" href="#debugging-builds" title="永久链接至标题">¶</a></h2>
|
||
<p>Python 可以附带某些宏来编译以启用对解释器和扩展模块的额外检查。 这些检查会给运行时增加大量额外开销因此它们默认未被启用。</p>
|
||
<p>A full list of the various types of debugging builds is in the file
|
||
<code class="file docutils literal notranslate"><span class="pre">Misc/SpecialBuilds.txt</span></code> in the Python source distribution. Builds are
|
||
available that support tracing of reference counts, debugging the memory
|
||
allocator, or low-level profiling of the main interpreter loop. Only the most
|
||
frequently-used builds will be described in the remainder of this section.</p>
|
||
<p>Compiling the interpreter with the <code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_DEBUG</span></code> macro defined produces
|
||
what is generally meant by "a debug build" of Python. <code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_DEBUG</span></code> is
|
||
enabled in the Unix build by adding <code class="docutils literal notranslate"><span class="pre">--with-pydebug</span></code> to the
|
||
<code class="file docutils literal notranslate"><span class="pre">./configure</span></code> command. It is also implied by the presence of the
|
||
not-Python-specific <code class="xref c c-macro docutils literal notranslate"><span class="pre">_DEBUG</span></code> macro. When <code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_DEBUG</span></code> is enabled
|
||
in the Unix build, compiler optimization is disabled.</p>
|
||
<p>除了前面描述的引用计数调试之外,还执行以下额外检查:</p>
|
||
<ul class="simple">
|
||
<li><p>额外检查将添加到对象分配器。</p></li>
|
||
<li><p>额外的检查将添加到解析器和编译器中。</p></li>
|
||
<li><p>检查从宽类型向窄类型的向下强转是否损失了信息。</p></li>
|
||
<li><p>许多断言被添加到字典和集合实现中。另外,集合对象需要 <code class="xref py py-meth docutils literal notranslate"><span class="pre">test_c_api()</span></code> 方法。</p></li>
|
||
<li><p>输入参数的完整性检查被添加到框架创建中。</p></li>
|
||
<li><p>使用已知的无效模式初始化整型的存储,以捕获对未初始化数字的引用。</p></li>
|
||
<li><p>添加底层跟踪和额外的异常检查到虚拟机的运行时中。</p></li>
|
||
<li><p>添加额外的检查到 arena 内存实现。</p></li>
|
||
<li><p>添加额外调试到线程模块。</p></li>
|
||
</ul>
|
||
<p>这里可能没有提到的额外的检查。</p>
|
||
<p>Defining <code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_TRACE_REFS</span></code> enables reference tracing. When defined, a
|
||
circular doubly linked list of active objects is maintained by adding two extra
|
||
fields to every <a class="reference internal" href="structures.html#c.PyObject" title="PyObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyObject</span></code></a>. Total allocations are tracked as well. Upon
|
||
exit, all existing references are printed. (In interactive mode this happens
|
||
after every statement run by the interpreter.) Implied by <code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_DEBUG</span></code>.</p>
|
||
<p>有关更多详细信息,请参阅Python源代码中的 <code class="file docutils literal notranslate"><span class="pre">Misc/SpecialBuilds.txt</span></code> 。</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="#coding-standards">代码标准</a></li>
|
||
<li><a class="reference internal" href="#include-files">包含文件</a></li>
|
||
<li><a class="reference internal" href="#useful-macros">有用的宏</a></li>
|
||
<li><a class="reference internal" href="#objects-types-and-reference-counts">对象、类型和引用计数</a><ul>
|
||
<li><a class="reference internal" href="#reference-counts">引用计数</a><ul>
|
||
<li><a class="reference internal" href="#reference-count-details">引用计数细节</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#types">类型</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#exceptions">异常</a></li>
|
||
<li><a class="reference internal" href="#embedding-python">嵌入Python</a></li>
|
||
<li><a class="reference internal" href="#debugging-builds">调试构建</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>上一个主题</h4>
|
||
<p class="topless"><a href="index.html"
|
||
title="上一章">Python/C API 参考手册</a></p>
|
||
<h4>下一个主题</h4>
|
||
<p class="topless"><a href="stable.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/c-api/intro.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="stable.html" title="稳定的应用程序二进制接口"
|
||
>下一页</a> |</li>
|
||
<li class="right" >
|
||
<a href="index.html" title="Python/C API 参考手册"
|
||
>上一页</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/C API 参考手册</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> |