增加python文档

This commit is contained in:
2025-03-09 17:10:56 +08:00
parent 7153217140
commit 723430cade
1039 changed files with 699509 additions and 0 deletions

View File

@@ -0,0 +1,361 @@
<!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>4. 构建C/C++扩展 &#8212; Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<script src="../_static/translations.js"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.8.20 文档 中搜索"
href="../_static/opensearch.xml"/>
<link rel="author" title="关于这些文档" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="copyright" title="版权所有" href="../copyright.html" />
<link rel="next" title="5. 在Windows平台编译C和C++扩展" href="windows.html" />
<link rel="prev" title="3. 定义扩展类型:已分类主题" href="newtypes.html" />
<link rel="canonical" href="https://docs.python.org/3/extending/building.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="#">4. 构建C/C++扩展</a><ul>
<li><a class="reference internal" href="#building-c-and-c-extensions-with-distutils">4.1. 使用distutils构建C和C++扩展</a></li>
<li><a class="reference internal" href="#distributing-your-extension-modules">4.2. 发布你的扩展模块</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="newtypes.html"
title="上一章"><span class="section-number">3. </span>定义扩展类型:已分类主题</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="windows.html"
title="下一章"><span class="section-number">5. </span>在Windows平台编译C和C++扩展</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/extending/building.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/extending/building.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="windows.html" title="5. 在Windows平台编译C和C++扩展"
accesskey="N">下一页</a> |</li>
<li class="right" >
<a href="newtypes.html" title="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> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">扩展和嵌入 Python 解释器</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="building-c-and-c-extensions">
<span id="building"></span><h1><span class="section-number">4. </span>构建C/C++扩展<a class="headerlink" href="#building-c-and-c-extensions" title="永久链接至标题"></a></h1>
<p>一个CPython的C扩展是一个共享库(例如一个Linux上的 <code class="docutils literal notranslate"><span class="pre">.so</span></code> 或者Windows上的 <code class="docutils literal notranslate"><span class="pre">.pyd</span></code> ),其会导出一个 <em>初始化函数</em></p>
<p>为了可导入,共享库必须在 <span class="target" id="index-4"></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> 中有效且必须命名遵循模块名字通过适当的扩展。当使用distutils时会自动生成正确的文件名。</p>
<p>初始化函数的声明如下:</p>
<dl class="function">
<dt id="c.PyInit_modulename">
<a class="reference internal" href="../c-api/structures.html#c.PyObject" title="PyObject">PyObject</a>* <code class="sig-name descname">PyInit_modulename</code><span class="sig-paren">(</span>void<span class="sig-paren">)</span><a class="headerlink" href="#c.PyInit_modulename" title="永久链接至目标"></a></dt>
<dd></dd></dl>
<p>该函数返回完整初始化过的模块,或一个 <a class="reference internal" href="../c-api/module.html#c.PyModuleDef" title="PyModuleDef"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyModuleDef</span></code></a> 实例。查看 <a class="reference internal" href="../c-api/module.html#initializing-modules"><span class="std std-ref">初始化 C 模块</span></a> 了解更多细节。</p>
<p>对于仅有ASCII编码的模块名函数必须是 <code class="docutils literal notranslate"><span class="pre">PyInit_&lt;modulename&gt;</span></code> ,将 <code class="docutils literal notranslate"><span class="pre">&lt;modulename&gt;</span></code> 替换为模块的名字。当使用 <a class="reference internal" href="../c-api/module.html#multi-phase-initialization"><span class="std std-ref">Multi-phase initialization</span></a>允许使用非ASCII编码的模块名。此时初始化函数的名字是 <code class="docutils literal notranslate"><span class="pre">PyInitU_&lt;modulename&gt;</span></code> ,而 <code class="docutils literal notranslate"><span class="pre">&lt;modulename&gt;</span></code> 需要用Python的 <em>punycode</em> 编码连字号需替换为下划线。在Python里:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">initfunc_name</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">suffix</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="n">name</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;ascii&#39;</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">UnicodeEncodeError</span><span class="p">:</span>
<span class="n">suffix</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;U_&#39;</span> <span class="o">+</span> <span class="n">name</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">&#39;punycode&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="sa">b</span><span class="s1">&#39;_&#39;</span><span class="p">)</span>
<span class="k">return</span> <span class="sa">b</span><span class="s1">&#39;PyInit&#39;</span> <span class="o">+</span> <span class="n">suffix</span>
</pre></div>
</div>
<p>可以在一个动态库里导出多个模块,通过定义多个初始化函数。而导入他们需要符号链接或自定义导入器,因为缺省时只有对应了文件名的函数才会被发现。查看 <em>&quot;一个库里的多模块&quot;</em> 章节,在 <span class="target" id="index-5"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0489"><strong>PEP 489</strong></a> 了解更多细节。</p>
<section id="building-c-and-c-extensions-with-distutils">
<h2><span class="section-number">4.1. </span>使用distutils构建C和C++扩展<a class="headerlink" href="#building-c-and-c-extensions-with-distutils" title="永久链接至标题"></a></h2>
<p>扩展模块可以用distutils来构建这是Python自带的。distutils也支持创建二进制包用户无需编译器而distutils就能安装扩展。</p>
<p>一个distutils包包含了一个驱动脚本 <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code> 。这是个纯Python文件大多数时候也很简单看起来如下</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">Extension</span>
<span class="n">module1</span> <span class="o">=</span> <span class="n">Extension</span><span class="p">(</span><span class="s1">&#39;demo&#39;</span><span class="p">,</span>
<span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;demo.c&#39;</span><span class="p">])</span>
<span class="n">setup</span> <span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s1">&#39;PackageName&#39;</span><span class="p">,</span>
<span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;1.0&#39;</span><span class="p">,</span>
<span class="n">description</span> <span class="o">=</span> <span class="s1">&#39;This is a demo package&#39;</span><span class="p">,</span>
<span class="n">ext_modules</span> <span class="o">=</span> <span class="p">[</span><span class="n">module1</span><span class="p">])</span>
</pre></div>
</div>
<p>通过文件 <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code> ,和文件 <code class="file docutils literal notranslate"><span class="pre">demo.c</span></code> ,运行如下</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">python</span><span class="w"> </span><span class="n">setup</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">build</span>
</pre></div>
</div>
<p>这会编译 <code class="file docutils literal notranslate"><span class="pre">demo.c</span></code> ,然后产生一个扩展模块叫做 <code class="docutils literal notranslate"><span class="pre">demo</span></code> 在目录 <code class="file docutils literal notranslate"><span class="pre">build</span></code> 里。依赖于系统,模块文件会放在某个子目录形如 <code class="file docutils literal notranslate"><span class="pre">build/lib.system</span></code> ,名字可能是 <code class="file docutils literal notranslate"><span class="pre">demo.so</span></code><code class="file docutils literal notranslate"><span class="pre">demo.pyd</span></code></p>
<p>在文件 <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code> 里,所有动作的入口通过 <code class="docutils literal notranslate"><span class="pre">setup</span></code> 函数。该函数可以接受可变数量个关键字参数上面的例子只使用了一个子集。特别需要注意的例子指定了构建包的元信息以及指定了包内容。通常一个包会包括多个模块就像Python的源码模块、文档、子包等。请参数distutils的文档<a class="reference internal" href="../distutils/index.html#distutils-index"><span class="std std-ref">分发 Python 模块(遗留版本)</span></a> 来了解更多distutils的特性本章节只解释构建扩展模块的部分。</p>
<p>通常预计算参数给 <code class="xref py py-func docutils literal notranslate"><span class="pre">setup()</span></code> ,想要更好的结构化驱动脚本。有如如上例子函数 <a class="reference internal" href="../distutils/apiref.html#distutils.core.setup" title="distutils.core.setup"><code class="xref py py-func docutils literal notranslate"><span class="pre">setup()</span></code></a><code class="docutils literal notranslate"><span class="pre">ext_modules</span></code> 参数是一列扩展模块,每个是一个 <code class="xref py py-class docutils literal notranslate"><span class="pre">Extension</span></code> 类的实例。例子中的实例定义了扩展命名为 <code class="docutils literal notranslate"><span class="pre">demo</span></code> ,从单一源码文件构建 <code class="file docutils literal notranslate"><span class="pre">demo.c</span></code></p>
<p>更多时候,构建一个扩展会复杂的多,需要额外的预处理器定义和库。如下例子展示了这些。</p>
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">Extension</span>
<span class="n">module1</span> <span class="o">=</span> <span class="n">Extension</span><span class="p">(</span><span class="s1">&#39;demo&#39;</span><span class="p">,</span>
<span class="n">define_macros</span> <span class="o">=</span> <span class="p">[(</span><span class="s1">&#39;MAJOR_VERSION&#39;</span><span class="p">,</span> <span class="s1">&#39;1&#39;</span><span class="p">),</span>
<span class="p">(</span><span class="s1">&#39;MINOR_VERSION&#39;</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)],</span>
<span class="n">include_dirs</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;/usr/local/include&#39;</span><span class="p">],</span>
<span class="n">libraries</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;tcl83&#39;</span><span class="p">],</span>
<span class="n">library_dirs</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;/usr/local/lib&#39;</span><span class="p">],</span>
<span class="n">sources</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;demo.c&#39;</span><span class="p">])</span>
<span class="n">setup</span> <span class="p">(</span><span class="n">name</span> <span class="o">=</span> <span class="s1">&#39;PackageName&#39;</span><span class="p">,</span>
<span class="n">version</span> <span class="o">=</span> <span class="s1">&#39;1.0&#39;</span><span class="p">,</span>
<span class="n">description</span> <span class="o">=</span> <span class="s1">&#39;This is a demo package&#39;</span><span class="p">,</span>
<span class="n">author</span> <span class="o">=</span> <span class="s1">&#39;Martin v. Loewis&#39;</span><span class="p">,</span>
<span class="n">author_email</span> <span class="o">=</span> <span class="s1">&#39;martin@v.loewis.de&#39;</span><span class="p">,</span>
<span class="n">url</span> <span class="o">=</span> <span class="s1">&#39;https://docs.python.org/extending/building&#39;</span><span class="p">,</span>
<span class="n">long_description</span> <span class="o">=</span> <span class="s1">&#39;&#39;&#39;</span>
<span class="s1">This is really just a demo package.</span>
<span class="s1">&#39;&#39;&#39;</span><span class="p">,</span>
<span class="n">ext_modules</span> <span class="o">=</span> <span class="p">[</span><span class="n">module1</span><span class="p">])</span>
</pre></div>
</div>
<p>例子中函数 <a class="reference internal" href="../distutils/apiref.html#distutils.core.setup" title="distutils.core.setup"><code class="xref py py-func docutils literal notranslate"><span class="pre">setup()</span></code></a> 在调用时额外传递了元信息是推荐发布包构建时的内容。对于这个扩展其指定了预处理器定义include目录库目录库。依赖于编译器distutils还会用其他方式传递信息给编译器。例如在Unix上结果是如下编译命令</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">gcc</span><span class="w"> </span><span class="o">-</span><span class="n">DNDEBUG</span><span class="w"> </span><span class="o">-</span><span class="n">g</span><span class="w"> </span><span class="o">-</span><span class="n">O3</span><span class="w"> </span><span class="o">-</span><span class="n">Wall</span><span class="w"> </span><span class="o">-</span><span class="n">Wstrict</span><span class="o">-</span><span class="n">prototypes</span><span class="w"> </span><span class="o">-</span><span class="n">fPIC</span><span class="w"> </span><span class="o">-</span><span class="n">DMAJOR_VERSION</span><span class="o">=</span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="n">DMINOR_VERSION</span><span class="o">=</span><span class="mi">0</span><span class="w"> </span><span class="o">-</span><span class="n">I</span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">include</span><span class="w"> </span><span class="o">-</span><span class="n">I</span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">include</span><span class="o">/</span><span class="n">python2</span><span class="mf">.2</span><span class="w"> </span><span class="o">-</span><span class="n">c</span><span class="w"> </span><span class="n">demo</span><span class="p">.</span><span class="n">c</span><span class="w"> </span><span class="o">-</span><span class="n">o</span><span class="w"> </span><span class="n">build</span><span class="o">/</span><span class="n">temp</span><span class="p">.</span><span class="n">linux</span><span class="o">-</span><span class="n">i686</span><span class="mf">-2.2</span><span class="o">/</span><span class="n">demo</span><span class="p">.</span><span class="n">o</span>
<span class="n">gcc</span><span class="w"> </span><span class="o">-</span><span class="n">shared</span><span class="w"> </span><span class="n">build</span><span class="o">/</span><span class="n">temp</span><span class="p">.</span><span class="n">linux</span><span class="o">-</span><span class="n">i686</span><span class="mf">-2.2</span><span class="o">/</span><span class="n">demo</span><span class="p">.</span><span class="n">o</span><span class="w"> </span><span class="o">-</span><span class="n">L</span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="n">lib</span><span class="w"> </span><span class="o">-</span><span class="n">ltcl83</span><span class="w"> </span><span class="o">-</span><span class="n">o</span><span class="w"> </span><span class="n">build</span><span class="o">/</span><span class="n">lib</span><span class="p">.</span><span class="n">linux</span><span class="o">-</span><span class="n">i686</span><span class="mf">-2.2</span><span class="o">/</span><span class="n">demo</span><span class="p">.</span><span class="n">so</span>
</pre></div>
</div>
<p>这些行代码仅用于展示目的distutils用户应该相信distutils能正确调用。</p>
</section>
<section id="distributing-your-extension-modules">
<span id="distributing"></span><h2><span class="section-number">4.2. </span>发布你的扩展模块<a class="headerlink" href="#distributing-your-extension-modules" title="永久链接至标题"></a></h2>
<p>当一个扩展已经成功地被构建时,有三种方式来使用它。</p>
<p>最终用户通常想要安装模块,可以这么运行</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">python</span><span class="w"> </span><span class="n">setup</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">install</span>
</pre></div>
</div>
<p>模块维护者应该制作源码包;要实现可以运行</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">python</span><span class="w"> </span><span class="n">setup</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">sdist</span>
</pre></div>
</div>
<p>有些情况下,需要在源码发布包里包含额外的文件;这通过 <code class="file docutils literal notranslate"><span class="pre">MANIFEST.in</span></code> 文件实现,查看 <a class="reference internal" href="../distutils/sourcedist.html#manifest"><span class="std std-ref">指定要分发的文件</span></a> 了解细节。</p>
<p>如果源码发行包被成功地构建,维护者还可以创建二进制发行包。 取决于具体平台,以下命令中的一个可以用来完成此任务</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">python</span><span class="w"> </span><span class="n">setup</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">bdist_wininst</span>
<span class="n">python</span><span class="w"> </span><span class="n">setup</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">bdist_rpm</span>
<span class="n">python</span><span class="w"> </span><span class="n">setup</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="n">bdist_dumb</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="#">4. 构建C/C++扩展</a><ul>
<li><a class="reference internal" href="#building-c-and-c-extensions-with-distutils">4.1. 使用distutils构建C和C++扩展</a></li>
<li><a class="reference internal" href="#distributing-your-extension-modules">4.2. 发布你的扩展模块</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="newtypes.html"
title="上一章"><span class="section-number">3. </span>定义扩展类型:已分类主题</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="windows.html"
title="下一章"><span class="section-number">5. </span>在Windows平台编译C和C++扩展</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/extending/building.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="windows.html" title="5. 在Windows平台编译C和C++扩展"
>下一页</a> |</li>
<li class="right" >
<a href="newtypes.html" title="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> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >扩展和嵌入 Python 解释器</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="footer">
&copy; <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
<br />
This page is licensed under the Python Software Foundation License Version 2.
<br />
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
<br />
<br />
The Python Software Foundation is a non-profit corporation.
<a href="https://www.python.org/psf/donations/">Please donate.</a>
<br />
<br />
最后更新于 12月 09, 2024.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
</div>
</body>
</html>

View File

@@ -0,0 +1,529 @@
<!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>1. 在其它应用程序嵌入 Python &#8212; Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<script src="../_static/translations.js"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.8.20 文档 中搜索"
href="../_static/opensearch.xml"/>
<link rel="author" title="关于这些文档" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="copyright" title="版权所有" href="../copyright.html" />
<link rel="next" title="Python/C API 参考手册" href="../c-api/index.html" />
<link rel="prev" title="5. 在Windows平台编译C和C++扩展" href="windows.html" />
<link rel="canonical" href="https://docs.python.org/3/extending/embedding.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="#">1. 在其它应用程序嵌入 Python</a><ul>
<li><a class="reference internal" href="#very-high-level-embedding">1.1. 高层次的嵌入</a></li>
<li><a class="reference internal" href="#beyond-very-high-level-embedding-an-overview">1.2. 突破高层次嵌入的限制:概述</a></li>
<li><a class="reference internal" href="#pure-embedding">1.3. 纯嵌入</a></li>
<li><a class="reference internal" href="#extending-embedded-python">1.4. 对嵌入 Python 功能进行扩展</a></li>
<li><a class="reference internal" href="#embedding-python-in-c">1.5. 在 C++ 中嵌入 Python</a></li>
<li><a class="reference internal" href="#compiling-and-linking-under-unix-like-systems">1.6. 在类 Unix 系统中编译和链接</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="windows.html"
title="上一章"><span class="section-number">5. </span>在Windows平台编译C和C++扩展</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="../c-api/index.html"
title="下一章">Python/C API 参考手册</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/extending/embedding.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/extending/embedding.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="../c-api/index.html" title="Python/C API 参考手册"
accesskey="N">下一页</a> |</li>
<li class="right" >
<a href="windows.html" title="5. 在Windows平台编译C和C++扩展"
accesskey="P">上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">扩展和嵌入 Python 解释器</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="embedding-python-in-another-application">
<span id="embedding"></span><h1><span class="section-number">1. </span>在其它应用程序嵌入 Python<a class="headerlink" href="#embedding-python-in-another-application" title="永久链接至标题"></a></h1>
<p>前几章讨论了如何对 Python 进行扩展,也就是如何用 C 函数库 扩展 Python 的功能。反过来也是可以的:将 Python 嵌入到 C/C++ 应用程序中丰富其功能。这种嵌入可以让应用程序用 Python 来实现某些功能,而不是用 C 或 C++ 。用途会有很多;比如允许用户用 Python 编写一些脚本,以便定制应用程序满足需求。如果某些功能用 Python 编写起来更为容易,那么开发人员自己也能这么干。</p>
<p>Python 的嵌入类似于扩展,但不完全相同。不同之处在于,扩展 Python 时应用程序的主程序仍然是 Python 解释器,而嵌入 Python 时的主程序可能与 Python 完全无关——而是应用程序的某些部分偶尔会调用 Python 解释器来运行一些 Python 代码。</p>
<p>因此,若要嵌入 Python就要提供自己的主程序。此主程序要做的事情之一就是初始化 Python 解释器。至少得调用函数 <a class="reference internal" href="../c-api/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 传递命令行参数。之后即可从应用程序的任何地方调用解释器了。</p>
<p>调用解释器的方式有好几种:可向 <a class="reference internal" href="../c-api/veryhigh.html#c.PyRun_SimpleString" title="PyRun_SimpleString"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyRun_SimpleString()</span></code></a> 传入一个包含 Python 语句的字符串,也可向 <a class="reference internal" href="../c-api/veryhigh.html#c.PyRun_SimpleFile" title="PyRun_SimpleFile"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyRun_SimpleFile()</span></code></a> 传入一个 stdio 文件指针和一个文件名(仅在错误信息中起到识别作用)。还可以调用前面介绍过的底层操作来构造并使用 Python 对象。</p>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<dl class="simple">
<dt><a class="reference internal" href="../c-api/index.html#c-api-index"><span class="std std-ref">Python/C API 参考手册</span></a></dt><dd><p>本文详细介绍了 Python 的 C 接口。这里有大量必要的信息。</p>
</dd>
</dl>
</div>
<section id="very-high-level-embedding">
<span id="high-level-embedding"></span><h2><span class="section-number">1.1. </span>高层次的嵌入<a class="headerlink" href="#very-high-level-embedding" title="永久链接至标题"></a></h2>
<p>最简单的 Python 嵌入形式就是采用非常高层的接口。该接口的目标是只执行一段 Python 脚本,而无需与应用程序直接交互。比如以下代码可以用来对某个文件进行一些操作。</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">&lt;Python.h&gt;</span>
<span class="kt">int</span>
<span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
<span class="w"> </span><span class="kt">wchar_t</span><span class="w"> </span><span class="o">*</span><span class="n">program</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Py_DecodeLocale</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="nb">NULL</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">program</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="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Fatal error: cannot decode argv[0]</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
<span class="w"> </span><span class="n">exit</span><span class="p">(</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_SetProgramName</span><span class="p">(</span><span class="n">program</span><span class="p">);</span><span class="w"> </span><span class="cm">/* optional but recommended */</span>
<span class="w"> </span><span class="n">Py_Initialize</span><span class="p">();</span>
<span class="w"> </span><span class="n">PyRun_SimpleString</span><span class="p">(</span><span class="s">&quot;from time import time,ctime</span><span class="se">\n</span><span class="s">&quot;</span>
<span class="w"> </span><span class="s">&quot;print(&#39;Today is&#39;, ctime(time()))</span><span class="se">\n</span><span class="s">&quot;</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">Py_FinalizeEx</span><span class="p">()</span><span class="w"> </span><span class="o">&lt;</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">exit</span><span class="p">(</span><span class="mi">120</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">PyMem_RawFree</span><span class="p">(</span><span class="n">program</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><a class="reference internal" href="../c-api/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="../c-api/init.html#c.Py_SetProgramName" title="Py_SetProgramName"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_SetProgramName()</span></code></a> 函数,以便向解释器告知 Python运行库的路径。接下来<a class="reference internal" href="../c-api/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="../c-api/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="../c-api/veryhigh.html#c.PyRun_SimpleFile" title="PyRun_SimpleFile"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyRun_SimpleFile()</span></code></a> 函数可以更好地从文件中获取 Python 代码,可省去分配内存空间和加载文件内容的麻烦。</p>
</section>
<section id="beyond-very-high-level-embedding-an-overview">
<span id="lower-level-embedding"></span><h2><span class="section-number">1.2. </span>突破高层次嵌入的限制:概述<a class="headerlink" href="#beyond-very-high-level-embedding-an-overview" title="永久链接至标题"></a></h2>
<p>高级接口能从应用程序中执行任何 Python 代码,但至少交换数据可说是相当麻烦的。如若需要交换数据,应使用较低级别的调用。几乎可以实现任何功能,代价是得写更多的 C 代码。</p>
<p>应该注意,尽管意图不同,但扩展 Python 和嵌入 Python 的过程相当类似。前几章中讨论的大多数主题依然有效。为了说明这一点,不妨来看一下从 Python 到 C 的扩展代码到底做了什么:</p>
<ol class="arabic simple">
<li><p>转换 Python 的数据值到 C,</p></li>
<li><p>用转换后的数据执行 C 程序的函数调用,以及</p></li>
<li><p>将调用返回的数据从 C 转换为 Python 格式。</p></li>
</ol>
<p>嵌入 Python 时,接口代码会这样做:</p>
<ol class="arabic simple">
<li><p>转换 C 的数据值到 Python,</p></li>
<li><p>用转换后的数据执行对 Python 接口的函数调用,</p></li>
<li><p>将调用返回的数据从 Python 转换为 C 格式。</p></li>
</ol>
<p>可见只是数据转换的步骤交换了一下顺序,以顺应跨语言的传输方向。唯一的区别是在两次数据转换之间调用的函数不同。在执行扩展时,调用一个 C 函数,而执行嵌入时调用的是个 Python 函数。</p>
<p>本文不会讨论如何将数据从 Python 转换到 C 去,反之亦然。另外还假定读者能够正确使用引用并处理错误。由于这些地方与解释器的扩展没有区别,请参考前面的章节以获得所需的信息。</p>
</section>
<section id="pure-embedding">
<span id="id1"></span><h2><span class="section-number">1.3. </span>纯嵌入<a class="headerlink" href="#pure-embedding" title="永久链接至标题"></a></h2>
<p>第一个程序的目标是执行 Python 脚本中的某个函数。就像高层次接口那样Python 解释器并不会直接与应用程序进行交互(但下一节将改变这一点)。</p>
<p>要运行 Python 脚本中定义的函数,代码如下:</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">&lt;Python.h&gt;</span>
<span class="kt">int</span>
<span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">argv</span><span class="p">[])</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">pName</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">pModule</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">pFunc</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">pArgs</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">pValue</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</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">argc</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span><span class="s">&quot;Usage: call pythonfile funcname [args]</span><span class="se">\n</span><span class="s">&quot;</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_Initialize</span><span class="p">();</span>
<span class="w"> </span><span class="n">pName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyUnicode_DecodeFSDefault</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="w"> </span><span class="cm">/* Error checking of pName left out */</span>
<span class="w"> </span><span class="n">pModule</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyImport_Import</span><span class="p">(</span><span class="n">pName</span><span class="p">);</span>
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">pName</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">pModule</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="n">pFunc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_GetAttrString</span><span class="p">(</span><span class="n">pModule</span><span class="p">,</span><span class="w"> </span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
<span class="w"> </span><span class="cm">/* pFunc is a new reference */</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pFunc</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">PyCallable_Check</span><span class="p">(</span><span class="n">pFunc</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">pArgs</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="n">argc</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">3</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">&lt;</span><span class="w"> </span><span class="n">argc</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">3</span><span class="p">;</span><span class="w"> </span><span class="o">++</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">pValue</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="n">atoi</span><span class="p">(</span><span class="n">argv</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">3</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">pValue</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">pArgs</span><span class="p">);</span>
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">pModule</span><span class="p">);</span>
<span class="w"> </span><span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Cannot convert argument</span><span class="se">\n</span><span class="s">&quot;</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="cm">/* pValue reference stolen here: */</span>
<span class="w"> </span><span class="n">PyTuple_SetItem</span><span class="p">(</span><span class="n">pArgs</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">pValue</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">pValue</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_CallObject</span><span class="p">(</span><span class="n">pFunc</span><span class="p">,</span><span class="w"> </span><span class="n">pArgs</span><span class="p">);</span>
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">pArgs</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">pValue</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="n">printf</span><span class="p">(</span><span class="s">&quot;Result of call: %ld</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">PyLong_AsLong</span><span class="p">(</span><span class="n">pValue</span><span class="p">));</span>
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">pValue</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">pFunc</span><span class="p">);</span>
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">pModule</span><span class="p">);</span>
<span class="w"> </span><span class="n">PyErr_Print</span><span class="p">();</span>
<span class="w"> </span><span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span><span class="s">&quot;Call failed</span><span class="se">\n</span><span class="s">&quot;</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="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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">PyErr_Occurred</span><span class="p">())</span>
<span class="w"> </span><span class="n">PyErr_Print</span><span class="p">();</span>
<span class="w"> </span><span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Cannot find function </span><span class="se">\&quot;</span><span class="s">%s</span><span class="se">\&quot;\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">pFunc</span><span class="p">);</span>
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">pModule</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">PyErr_Print</span><span class="p">();</span>
<span class="w"> </span><span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Failed to load </span><span class="se">\&quot;</span><span class="s">%s</span><span class="se">\&quot;\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">argv</span><span class="p">[</span><span class="mi">1</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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">Py_FinalizeEx</span><span class="p">()</span><span class="w"> </span><span class="o">&lt;</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="k">return</span><span class="w"> </span><span class="mi">120</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>上述代码先利用 <code class="docutils literal notranslate"><span class="pre">argv[1]</span></code> 加载 Python 脚本,再调用 <code class="docutils literal notranslate"><span class="pre">argv[2]</span></code> 指定的函数。函数的整数参数是 <code class="docutils literal notranslate"><span class="pre">argv</span></code> 数组中的其余值。如果 <a class="reference internal" href="#compiling"><span class="std std-ref">编译并链接</span></a> 该程序(此处将最终的可执行程序称作 <strong class="program">call</strong>, 并用它执行一个 Python 脚本,例如:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">multiply</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Will compute&quot;</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="s2">&quot;times&quot;</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="n">c</span> <span class="o">=</span> <span class="mi">0</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="n">a</span><span class="p">):</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">c</span> <span class="o">+</span> <span class="n">b</span>
<span class="k">return</span> <span class="n">c</span>
</pre></div>
</div>
<p>然后结果应该是:</p>
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>call<span class="w"> </span>multiply<span class="w"> </span>multiply<span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="m">2</span>
<span class="go">Will compute 3 times 2</span>
<span class="go">Result of call: 6</span>
</pre></div>
</div>
<p>尽管相对其功能而言,该程序体积相当庞大,但大部分代码是用于 Python 和 C 之间的数据转换,以及报告错误。嵌入 Python 的有趣部分从此开始:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Py_Initialize</span><span class="p">();</span>
<span class="n">pName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyUnicode_DecodeFSDefault</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="cm">/* Error checking of pName left out */</span>
<span class="n">pModule</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyImport_Import</span><span class="p">(</span><span class="n">pName</span><span class="p">);</span>
</pre></div>
</div>
<p>初始化解释器之后,则用 <a class="reference internal" href="../c-api/import.html#c.PyImport_Import" title="PyImport_Import"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyImport_Import()</span></code></a> 加载脚本。此函数的参数需是个 Python 字符串,一个用 <a class="reference internal" href="../c-api/unicode.html#c.PyUnicode_FromString" title="PyUnicode_FromString"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyUnicode_FromString()</span></code></a> 数据转换函数构建的字符串。</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">pFunc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_GetAttrString</span><span class="p">(</span><span class="n">pModule</span><span class="p">,</span><span class="w"> </span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span>
<span class="cm">/* pFunc is a new reference */</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pFunc</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">PyCallable_Check</span><span class="p">(</span><span class="n">pFunc</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">...</span>
<span class="p">}</span>
<span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">pFunc</span><span class="p">);</span>
</pre></div>
</div>
<p>脚本一旦加载完毕,就会用 <a class="reference internal" href="../c-api/object.html#c.PyObject_GetAttrString" title="PyObject_GetAttrString"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_GetAttrString()</span></code></a> 查找属性名称。如果名称存在,并且返回的是可调用对象,即可安全地视其为函数。然后程序继续执行,照常构建由参数组成的元组。然后用以下方式调用 Python 函数:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">pValue</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_CallObject</span><span class="p">(</span><span class="n">pFunc</span><span class="p">,</span><span class="w"> </span><span class="n">pArgs</span><span class="p">);</span>
</pre></div>
</div>
<p>当函数返回时,<code class="docutils literal notranslate"><span class="pre">pValue</span></code> 要么为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>,要么包含对函数返回值的引用。请确保用完后释放该引用。</p>
</section>
<section id="extending-embedded-python">
<span id="extending-with-embedding"></span><h2><span class="section-number">1.4. </span>对嵌入 Python 功能进行扩展<a class="headerlink" href="#extending-embedded-python" title="永久链接至标题"></a></h2>
<p>到目前为止,嵌入的 Python 解释器还不能访问应用程序本身的功能。Python API 通过扩展嵌入解释器实现了这一点。 也就是说,用应用程序提供的函数对嵌入的解释器进行扩展。虽然听起来有些复杂,但也没那么糟糕。只要暂时忘记是应用程序启动了 Python 解释器。而把应用程序看作是一堆子程序,然后写一些胶水代码让 Python 访问这些子程序,就像编写普通的 Python 扩展程序一样。 例如:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">numargs</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="cm">/* Return the number of arguments of the application command line */</span>
<span class="k">static</span><span class="w"> </span><span class="n">PyObject</span><span class="o">*</span>
<span class="nf">emb_numargs</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</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">args</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTuple</span><span class="p">(</span><span class="n">args</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;:numargs&quot;</span><span class="p">))</span>
<span class="w"> </span><span class="k">return</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="n">PyLong_FromLong</span><span class="p">(</span><span class="n">numargs</span><span class="p">);</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">EmbMethods</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">&quot;numargs&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">emb_numargs</span><span class="p">,</span><span class="w"> </span><span class="n">METH_VARARGS</span><span class="p">,</span>
<span class="w"> </span><span class="s">&quot;Return the number of arguments received by the process.&quot;</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="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">}</span>
<span class="p">};</span>
<span class="k">static</span><span class="w"> </span><span class="n">PyModuleDef</span><span class="w"> </span><span class="n">EmbModule</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PyModuleDef_HEAD_INIT</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;emb&quot;</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</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">EmbMethods</span><span class="p">,</span>
<span class="w"> </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="w"> </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="k">static</span><span class="w"> </span><span class="n">PyObject</span><span class="o">*</span>
<span class="nf">PyInit_emb</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">PyModule_Create</span><span class="p">(</span><span class="o">&amp;</span><span class="n">EmbModule</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="xref c c-func docutils literal notranslate"><span class="pre">main()</span></code> 函数之前插入上述代码。并在调用 <a class="reference internal" href="../c-api/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> 之前插入以下两条语句:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">numargs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">argc</span><span class="p">;</span>
<span class="n">PyImport_AppendInittab</span><span class="p">(</span><span class="s">&quot;emb&quot;</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">PyInit_emb</span><span class="p">);</span>
</pre></div>
</div>
<p>这两行代码初始化了 <code class="docutils literal notranslate"><span class="pre">numargs</span></code> 变量,并让 <code class="xref py py-func docutils literal notranslate"><span class="pre">emb.numargs()</span></code> 函数能被嵌入的 Python 解释器访问到。有了这些扩展Python 脚本可以执行类似以下功能:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">emb</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Number of arguments&quot;</span><span class="p">,</span> <span class="n">emb</span><span class="o">.</span><span class="n">numargs</span><span class="p">())</span>
</pre></div>
</div>
<p>在真实的应用程序中,这种方法将把应用的 API 暴露给 Python 使用。</p>
</section>
<section id="embedding-python-in-c">
<span id="embeddingincplusplus"></span><h2><span class="section-number">1.5. </span>在 C++ 中嵌入 Python<a class="headerlink" href="#embedding-python-in-c" title="永久链接至标题"></a></h2>
<p>还可以将 Python 嵌入到 C++ 程序中去;确切地说,实现方式将取决于 C++ 系统的实现细节;一般需用 C++ 编写主程序,并用 C++ 编译器来编译和链接 程序。不需要用 C++ 重新编译 Python 本身。</p>
</section>
<section id="compiling-and-linking-under-unix-like-systems">
<span id="compiling"></span><h2><span class="section-number">1.6. </span>在类 Unix 系统中编译和链接<a class="headerlink" href="#compiling-and-linking-under-unix-like-systems" title="永久链接至标题"></a></h2>
<p>为了将 Python 解释器嵌入应用程序,找到正确的编译参数传给编译器 (和链接器) 并非易事,特别是因为 Python 加载的库模块是以 C 动态扩展(<code class="file docutils literal notranslate"><span class="pre">.so</span></code> 文件)的形式实现的。</p>
<p>为了得到所需的编译器和链接器参数,可执行 <code class="file docutils literal notranslate"><span class="pre">python</span><em><span class="pre">X.Y</span></em><span class="pre">-config</span></code> 脚本,它是在安装 Python 时生成的(也可能存在 <code class="file docutils literal notranslate"><span class="pre">python3-config</span></code> 脚本)。该脚本有几个参数,其中以下几个参数会直接有用:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">pythonX.Y-config</span> <span class="pre">--cflags</span></code> 将给出建议的编译参数。</p>
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>/opt/bin/python3.4-config<span class="w"> </span>--cflags
<span class="go">-I/opt/include/python3.4m -I/opt/include/python3.4m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes</span>
</pre></div>
</div>
</li>
<li><p><code class="docutils literal notranslate"><span class="pre">pythonX.Y-config</span> <span class="pre">--ldflags</span></code> 将给出建议的链接参数。</p>
<div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>/opt/bin/python3.4-config<span class="w"> </span>--ldflags
<span class="go">-L/opt/lib/python3.4/config-3.4m -lpthread -ldl -lutil -lm -lpython3.4m -Xlinker -export-dynamic</span>
</pre></div>
</div>
</li>
</ul>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>为了避免多个 Python 安装版本引发混乱(特别是在系统安装版本和自己编译版本之间),建议用 <code class="file docutils literal notranslate"><span class="pre">python</span><em><span class="pre">X.Y</span></em><span class="pre">-config</span></code> 指定绝对路径,如上例所述。</p>
</div>
<p>如果上述方案不起作用(不能保证对所有 Unix 类平台都生效;欢迎提出 <a class="reference internal" href="../bugs.html#reporting-bugs"><span class="std std-ref">bug 报告</span></a>),就得阅读系统关于动态链接的文档,并检查 Python 的 <code class="file docutils literal notranslate"><span class="pre">Makefile</span></code> (用 <a class="reference internal" href="../library/sysconfig.html#sysconfig.get_makefile_filename" title="sysconfig.get_makefile_filename"><code class="xref py py-func docutils literal notranslate"><span class="pre">sysconfig.get_makefile_filename()</span></code></a> 找到所在位置)和编译参数。这时 <a class="reference internal" href="../library/sysconfig.html#module-sysconfig" title="sysconfig: Python's configuration information"><code class="xref py py-mod docutils literal notranslate"><span class="pre">sysconfig</span></code></a> 模块会是个有用的工具,可用编程方式提取需组合在一起的配置值。比如:</p>
<div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">sysconfig</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">sysconfig</span><span class="o">.</span><span class="n">get_config_var</span><span class="p">(</span><span class="s1">&#39;LIBS&#39;</span><span class="p">)</span>
<span class="go">&#39;-lpthread -ldl -lutil&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">sysconfig</span><span class="o">.</span><span class="n">get_config_var</span><span class="p">(</span><span class="s1">&#39;LINKFORSHARED&#39;</span><span class="p">)</span>
<span class="go">&#39;-Xlinker -export-dynamic&#39;</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="#">1. 在其它应用程序嵌入 Python</a><ul>
<li><a class="reference internal" href="#very-high-level-embedding">1.1. 高层次的嵌入</a></li>
<li><a class="reference internal" href="#beyond-very-high-level-embedding-an-overview">1.2. 突破高层次嵌入的限制:概述</a></li>
<li><a class="reference internal" href="#pure-embedding">1.3. 纯嵌入</a></li>
<li><a class="reference internal" href="#extending-embedded-python">1.4. 对嵌入 Python 功能进行扩展</a></li>
<li><a class="reference internal" href="#embedding-python-in-c">1.5. 在 C++ 中嵌入 Python</a></li>
<li><a class="reference internal" href="#compiling-and-linking-under-unix-like-systems">1.6. 在类 Unix 系统中编译和链接</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="windows.html"
title="上一章"><span class="section-number">5. </span>在Windows平台编译C和C++扩展</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="../c-api/index.html"
title="下一章">Python/C API 参考手册</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/extending/embedding.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="../c-api/index.html" title="Python/C API 参考手册"
>下一页</a> |</li>
<li class="right" >
<a href="windows.html" title="5. 在Windows平台编译C和C++扩展"
>上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >扩展和嵌入 Python 解释器</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="footer">
&copy; <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
<br />
This page is licensed under the Python Software Foundation License Version 2.
<br />
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
<br />
<br />
The Python Software Foundation is a non-profit corporation.
<a href="https://www.python.org/psf/donations/">Please donate.</a>
<br />
<br />
最后更新于 12月 09, 2024.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,353 @@
<!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 解释器 &#8212; Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<script src="../_static/translations.js"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.8.20 文档 中搜索"
href="../_static/opensearch.xml"/>
<link rel="author" title="关于这些文档" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="copyright" title="版权所有" href="../copyright.html" />
<link rel="next" title="1. 使用 C 或 C++ 扩展 Python" href="extending.html" />
<link rel="prev" title="未创建文档的模块" href="../library/undoc.html" />
<link rel="canonical" href="https://docs.python.org/3/extending/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>
<h3><a href="../contents.html">目录</a></h3>
<ul>
<li><a class="reference internal" href="#">扩展和嵌入 Python 解释器</a><ul>
<li><a class="reference internal" href="#recommended-third-party-tools">推荐的第三方工具</a></li>
<li><a class="reference internal" href="#creating-extensions-without-third-party-tools">不使用第三方工具创建扩展</a></li>
<li><a class="reference internal" href="#embedding-the-cpython-runtime-in-a-larger-application">在更大的应用程序中嵌入 CPython 运行时</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="../library/undoc.html"
title="上一章">未创建文档的模块</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="extending.html"
title="下一章"><span class="section-number">1. </span>使用 C 或 C++ 扩展 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/extending/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/extending/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="extending.html" title="1. 使用 C 或 C++ 扩展 Python"
accesskey="N">下一页</a> |</li>
<li class="right" >
<a href="../library/undoc.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> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="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="extending-and-embedding-the-python-interpreter">
<span id="extending-index"></span><h1>扩展和嵌入 Python 解释器<a class="headerlink" href="#extending-and-embedding-the-python-interpreter" title="永久链接至标题"></a></h1>
<p>本文档描述了如何使用 C 或 C++ 编写模块以使用新模块来扩展 Python 解释器的功能。 这些模块不仅可以定义新的函数,还可以定义新的对象类型及其方法。 该文档还描述了如何将 Python 解释器嵌入到另一个应用程序中,以用作扩展语言。 最后,它展示了如何编译和链接扩展模块,以便它们可以动态地(在运行时)加载到解释器中,如果底层操作系统支持此特性的话。</p>
<p>本文档假设你具备有关 Python 的基本知识。有关该语言的非正式介绍,请参阅 <a class="reference internal" href="../tutorial/index.html#tutorial-index"><span class="std std-ref">Python 教程</span></a><a class="reference internal" href="../reference/index.html#reference-index"><span class="std std-ref">Python语言参考</span></a> 给出了更正式的语言定义。 <a class="reference internal" href="../library/index.html#library-index"><span class="std std-ref">Python 标准库</span></a> 包含现有的对象类型、函数和模块(内置和用 Python 编写)的文档,使语言具有广泛的应用范围。</p>
<p>关于整个 Python/C API 的详细介绍,请参阅独立的 <a class="reference internal" href="../c-api/index.html#c-api-index"><span class="std std-ref">Python/C API 参考手册</span></a></p>
<section id="recommended-third-party-tools">
<h2>推荐的第三方工具<a class="headerlink" href="#recommended-third-party-tools" title="永久链接至标题"></a></h2>
<p>本指南仅介绍了作为此 CPython 版本的一部分提供的创建扩展的基本工具。 第三方工具,如 <a class="reference external" href="http://cython.org/">Cython</a><a class="reference external" href="https://cffi.readthedocs.io">cffi</a><a class="reference external" href="http://www.swig.org">SWIG</a><a class="reference external" href="https://numba.pydata.org/">Numba</a> 提供了更简单和更复杂的方法来为 Python 创建 C 和 C ++ 扩展。</p>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<dl class="simple">
<dt><a class="reference external" href="https://packaging.python.org/guides/packaging-binary-extensions/">Python Packaging User Guide: Binary Extensions</a></dt><dd><p>“ Python Packaging User Guide ”不仅涵盖了几个简化二进制扩展创建的可用工具,还讨论了为什么首先创建扩展模块的各种原因。</p>
</dd>
</dl>
</div>
</section>
<section id="creating-extensions-without-third-party-tools">
<h2>不使用第三方工具创建扩展<a class="headerlink" href="#creating-extensions-without-third-party-tools" title="永久链接至标题"></a></h2>
<p>本指南的这一部分包括在没有第三方工具帮助的情况下创建 C 和 C ++ 扩展。它主要用于这些工具的创建者,而不是建议你创建自己的 C 扩展的方法。</p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="extending.html">1. 使用 C 或 C++ 扩展 Python</a><ul>
<li class="toctree-l2"><a class="reference internal" href="extending.html#a-simple-example">1.1. 一个简单的例子</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#intermezzo-errors-and-exceptions">1.2. 关于错误和异常</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#back-to-the-example">1.3. 回到例子</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#the-module-s-method-table-and-initialization-function">1.4. 模块方法表和初始化函数</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#compilation-and-linkage">1.5. 编译和链接</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#calling-python-functions-from-c">1.6. 在C中调用Python函数</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#extracting-parameters-in-extension-functions">1.7. 提取扩展函数的参数</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#keyword-parameters-for-extension-functions">1.8. 给扩展函数的关键字参数</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#building-arbitrary-values">1.9. 构造任意值</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#reference-counts">1.10. 引用计数</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#writing-extensions-in-c">1.11. 在C++中编写扩展</a></li>
<li class="toctree-l2"><a class="reference internal" href="extending.html#providing-a-c-api-for-an-extension-module">1.12. 给扩展模块提供C API</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="newtypes_tutorial.html">2. 自定义扩展类型:教程</a><ul>
<li class="toctree-l2"><a class="reference internal" href="newtypes_tutorial.html#the-basics">2.1. 基础</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes_tutorial.html#adding-data-and-methods-to-the-basic-example">2.2. 向基本示例添加数据和方法</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes_tutorial.html#providing-finer-control-over-data-attributes">2.3. 提供对于数据属性的更精细控制</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes_tutorial.html#supporting-cyclic-garbage-collection">2.4. 支持循环垃圾回收</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes_tutorial.html#subclassing-other-types">2.5. 子类化其他类型</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="newtypes.html">3. 定义扩展类型:已分类主题</a><ul>
<li class="toctree-l2"><a class="reference internal" href="newtypes.html#finalization-and-de-allocation">3.1. 终结和内存释放</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes.html#object-presentation">3.2. 对象展示</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes.html#attribute-management">3.3. 属性管理</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes.html#object-comparison">3.4. 对象比较</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes.html#abstract-protocol-support">3.5. 抽象协议支持</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes.html#weak-reference-support">3.6. 弱引用支持</a></li>
<li class="toctree-l2"><a class="reference internal" href="newtypes.html#more-suggestions">3.7. 更多建议</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="building.html">4. 构建C/C++扩展</a><ul>
<li class="toctree-l2"><a class="reference internal" href="building.html#building-c-and-c-extensions-with-distutils">4.1. 使用distutils构建C和C++扩展</a></li>
<li class="toctree-l2"><a class="reference internal" href="building.html#distributing-your-extension-modules">4.2. 发布你的扩展模块</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="windows.html">5. 在Windows平台编译C和C++扩展</a><ul>
<li class="toctree-l2"><a class="reference internal" href="windows.html#a-cookbook-approach">5.1. 菜谱式说明</a></li>
<li class="toctree-l2"><a class="reference internal" href="windows.html#differences-between-unix-and-windows">5.2. Unix 和 Windows 之间的差异</a></li>
<li class="toctree-l2"><a class="reference internal" href="windows.html#using-dlls-in-practice">5.3. DLL 的实际使用</a></li>
</ul>
</li>
</ul>
</div>
</section>
<section id="embedding-the-cpython-runtime-in-a-larger-application">
<h2>在更大的应用程序中嵌入 CPython 运行时<a class="headerlink" href="#embedding-the-cpython-runtime-in-a-larger-application" title="永久链接至标题"></a></h2>
<p>有时,不是要创建在 Python 解释器中作为主应用程序运行的扩展,而是希望将 CPython 运行时嵌入到更大的应用程序中。 本节介绍了成功完成此操作所涉及的一些细节。</p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="embedding.html">1. 在其它应用程序嵌入 Python</a><ul>
<li class="toctree-l2"><a class="reference internal" href="embedding.html#very-high-level-embedding">1.1. 高层次的嵌入</a></li>
<li class="toctree-l2"><a class="reference internal" href="embedding.html#beyond-very-high-level-embedding-an-overview">1.2. 突破高层次嵌入的限制:概述</a></li>
<li class="toctree-l2"><a class="reference internal" href="embedding.html#pure-embedding">1.3. 纯嵌入</a></li>
<li class="toctree-l2"><a class="reference internal" href="embedding.html#extending-embedded-python">1.4. 对嵌入 Python 功能进行扩展</a></li>
<li class="toctree-l2"><a class="reference internal" href="embedding.html#embedding-python-in-c">1.5. 在 C++ 中嵌入 Python</a></li>
<li class="toctree-l2"><a class="reference internal" href="embedding.html#compiling-and-linking-under-unix-like-systems">1.6. 在类 Unix 系统中编译和链接</a></li>
</ul>
</li>
</ul>
</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="#">扩展和嵌入 Python 解释器</a><ul>
<li><a class="reference internal" href="#recommended-third-party-tools">推荐的第三方工具</a></li>
<li><a class="reference internal" href="#creating-extensions-without-third-party-tools">不使用第三方工具创建扩展</a></li>
<li><a class="reference internal" href="#embedding-the-cpython-runtime-in-a-larger-application">在更大的应用程序中嵌入 CPython 运行时</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="../library/undoc.html"
title="上一章">未创建文档的模块</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="extending.html"
title="下一章"><span class="section-number">1. </span>使用 C 或 C++ 扩展 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/extending/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="extending.html" title="1. 使用 C 或 C++ 扩展 Python"
>下一页</a> |</li>
<li class="right" >
<a href="../library/undoc.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> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="footer">
&copy; <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
<br />
This page is licensed under the Python Software Foundation License Version 2.
<br />
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
<br />
<br />
The Python Software Foundation is a non-profit corporation.
<a href="https://www.python.org/psf/donations/">Please donate.</a>
<br />
<br />
最后更新于 12月 09, 2024.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
</div>
</body>
</html>

View File

@@ -0,0 +1,739 @@
<!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>3. 定义扩展类型:已分类主题 &#8212; Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<script src="../_static/translations.js"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.8.20 文档 中搜索"
href="../_static/opensearch.xml"/>
<link rel="author" title="关于这些文档" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="copyright" title="版权所有" href="../copyright.html" />
<link rel="next" title="4. 构建C/C++扩展" href="building.html" />
<link rel="prev" title="2. 自定义扩展类型:教程" href="newtypes_tutorial.html" />
<link rel="canonical" href="https://docs.python.org/3/extending/newtypes.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="#">3. 定义扩展类型:已分类主题</a><ul>
<li><a class="reference internal" href="#finalization-and-de-allocation">3.1. 终结和内存释放</a></li>
<li><a class="reference internal" href="#object-presentation">3.2. 对象展示</a></li>
<li><a class="reference internal" href="#attribute-management">3.3. 属性管理</a><ul>
<li><a class="reference internal" href="#generic-attribute-management">3.3.1. 泛型属性管理</a></li>
<li><a class="reference internal" href="#type-specific-attribute-management">3.3.2. 类型专属的属性管理</a></li>
</ul>
</li>
<li><a class="reference internal" href="#object-comparison">3.4. 对象比较</a></li>
<li><a class="reference internal" href="#abstract-protocol-support">3.5. 抽象协议支持</a></li>
<li><a class="reference internal" href="#weak-reference-support">3.6. 弱引用支持</a></li>
<li><a class="reference internal" href="#more-suggestions">3.7. 更多建议</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="newtypes_tutorial.html"
title="上一章"><span class="section-number">2. </span>自定义扩展类型:教程</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="building.html"
title="下一章"><span class="section-number">4. </span>构建C/C++扩展</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/extending/newtypes.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/extending/newtypes.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="building.html" title="4. 构建C/C++扩展"
accesskey="N">下一页</a> |</li>
<li class="right" >
<a href="newtypes_tutorial.html" title="2. 自定义扩展类型:教程"
accesskey="P">上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">扩展和嵌入 Python 解释器</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="defining-extension-types-assorted-topics">
<span id="new-types-topics"></span><h1><span class="section-number">3. </span>定义扩展类型:已分类主题<a class="headerlink" href="#defining-extension-types-assorted-topics" title="永久链接至标题"></a></h1>
<p id="dnt-type-methods">本章节目标是提供一个各种你可以实现的类型方法及其功能的简短介绍。</p>
<p>这是C类型 <a class="reference internal" href="../c-api/type.html#c.PyTypeObject" title="PyTypeObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyTypeObject</span></code></a> 的定义,省略了只用于调试构建的字段:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_typeobject</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PyObject_VAR_HEAD</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">tp_name</span><span class="p">;</span><span class="w"> </span><span class="cm">/* For printing, in format &quot;&lt;module&gt;.&lt;name&gt;&quot; */</span>
<span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">tp_basicsize</span><span class="p">,</span><span class="w"> </span><span class="n">tp_itemsize</span><span class="p">;</span><span class="w"> </span><span class="cm">/* For allocation */</span>
<span class="w"> </span><span class="cm">/* Methods to implement standard operations */</span>
<span class="w"> </span><span class="n">destructor</span><span class="w"> </span><span class="n">tp_dealloc</span><span class="p">;</span>
<span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">tp_vectorcall_offset</span><span class="p">;</span>
<span class="w"> </span><span class="n">getattrfunc</span><span class="w"> </span><span class="n">tp_getattr</span><span class="p">;</span>
<span class="w"> </span><span class="n">setattrfunc</span><span class="w"> </span><span class="n">tp_setattr</span><span class="p">;</span>
<span class="w"> </span><span class="n">PyAsyncMethods</span><span class="w"> </span><span class="o">*</span><span class="n">tp_as_async</span><span class="p">;</span><span class="w"> </span><span class="cm">/* formerly known as tp_compare (Python 2)</span>
<span class="cm"> or tp_reserved (Python 3) */</span>
<span class="w"> </span><span class="n">reprfunc</span><span class="w"> </span><span class="n">tp_repr</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* Method suites for standard classes */</span>
<span class="w"> </span><span class="n">PyNumberMethods</span><span class="w"> </span><span class="o">*</span><span class="n">tp_as_number</span><span class="p">;</span>
<span class="w"> </span><span class="n">PySequenceMethods</span><span class="w"> </span><span class="o">*</span><span class="n">tp_as_sequence</span><span class="p">;</span>
<span class="w"> </span><span class="n">PyMappingMethods</span><span class="w"> </span><span class="o">*</span><span class="n">tp_as_mapping</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* More standard operations (here for binary compatibility) */</span>
<span class="w"> </span><span class="n">hashfunc</span><span class="w"> </span><span class="n">tp_hash</span><span class="p">;</span>
<span class="w"> </span><span class="n">ternaryfunc</span><span class="w"> </span><span class="n">tp_call</span><span class="p">;</span>
<span class="w"> </span><span class="n">reprfunc</span><span class="w"> </span><span class="n">tp_str</span><span class="p">;</span>
<span class="w"> </span><span class="n">getattrofunc</span><span class="w"> </span><span class="n">tp_getattro</span><span class="p">;</span>
<span class="w"> </span><span class="n">setattrofunc</span><span class="w"> </span><span class="n">tp_setattro</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* Functions to access object as input/output buffer */</span>
<span class="w"> </span><span class="n">PyBufferProcs</span><span class="w"> </span><span class="o">*</span><span class="n">tp_as_buffer</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* Flags to define presence of optional/expanded features */</span>
<span class="w"> </span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">tp_flags</span><span class="p">;</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">tp_doc</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Documentation string */</span>
<span class="w"> </span><span class="cm">/* call function for all accessible objects */</span>
<span class="w"> </span><span class="n">traverseproc</span><span class="w"> </span><span class="n">tp_traverse</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* delete references to contained objects */</span>
<span class="w"> </span><span class="n">inquiry</span><span class="w"> </span><span class="n">tp_clear</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* rich comparisons */</span>
<span class="w"> </span><span class="n">richcmpfunc</span><span class="w"> </span><span class="n">tp_richcompare</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* weak reference enabler */</span>
<span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">tp_weaklistoffset</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* Iterators */</span>
<span class="w"> </span><span class="n">getiterfunc</span><span class="w"> </span><span class="n">tp_iter</span><span class="p">;</span>
<span class="w"> </span><span class="n">iternextfunc</span><span class="w"> </span><span class="n">tp_iternext</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* Attribute descriptor and subclassing stuff */</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">PyMethodDef</span><span class="w"> </span><span class="o">*</span><span class="n">tp_methods</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">PyMemberDef</span><span class="w"> </span><span class="o">*</span><span class="n">tp_members</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">PyGetSetDef</span><span class="w"> </span><span class="o">*</span><span class="n">tp_getset</span><span class="p">;</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">_typeobject</span><span class="w"> </span><span class="o">*</span><span class="n">tp_base</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">tp_dict</span><span class="p">;</span>
<span class="w"> </span><span class="n">descrgetfunc</span><span class="w"> </span><span class="n">tp_descr_get</span><span class="p">;</span>
<span class="w"> </span><span class="n">descrsetfunc</span><span class="w"> </span><span class="n">tp_descr_set</span><span class="p">;</span>
<span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">tp_dictoffset</span><span class="p">;</span>
<span class="w"> </span><span class="n">initproc</span><span class="w"> </span><span class="n">tp_init</span><span class="p">;</span>
<span class="w"> </span><span class="n">allocfunc</span><span class="w"> </span><span class="n">tp_alloc</span><span class="p">;</span>
<span class="w"> </span><span class="n">newfunc</span><span class="w"> </span><span class="n">tp_new</span><span class="p">;</span>
<span class="w"> </span><span class="n">freefunc</span><span class="w"> </span><span class="n">tp_free</span><span class="p">;</span><span class="w"> </span><span class="cm">/* Low-level free-memory routine */</span>
<span class="w"> </span><span class="n">inquiry</span><span class="w"> </span><span class="n">tp_is_gc</span><span class="p">;</span><span class="w"> </span><span class="cm">/* For PyObject_IS_GC */</span>
<span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">tp_bases</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">tp_mro</span><span class="p">;</span><span class="w"> </span><span class="cm">/* method resolution order */</span>
<span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">tp_cache</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">tp_subclasses</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">tp_weaklist</span><span class="p">;</span>
<span class="w"> </span><span class="n">destructor</span><span class="w"> </span><span class="n">tp_del</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* Type attribute cache version tag. Added in version 2.6 */</span>
<span class="w"> </span><span class="kt">unsigned</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">tp_version_tag</span><span class="p">;</span>
<span class="w"> </span><span class="n">destructor</span><span class="w"> </span><span class="n">tp_finalize</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">PyTypeObject</span><span class="p">;</span>
</pre></div>
</div>
<p>这里有 <em>很多</em> 方法。但是不要太担心,如果你要定义一个类型,通常只需要实现少量的方法。</p>
<p>正如你猜到的一样,我们正要一步一步详细介绍各种处理程序。因为有大量的历史包袱影响字段的排序,所以我们不会根据它们在结构体里定义的顺序讲解。通常非常容易找到一个包含你需要的字段的例子,然后改变值去适应你新的类型。</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">tp_name</span><span class="p">;</span><span class="w"> </span><span class="cm">/* For printing */</span>
</pre></div>
</div>
<p>类型的名字 - 上一章提到过的,会出现在很多地方,几乎全部都是为了诊断目的。尝试选择一个好名字,对于诊断很有帮助。</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">tp_basicsize</span><span class="p">,</span><span class="w"> </span><span class="n">tp_itemsize</span><span class="p">;</span><span class="w"> </span><span class="cm">/* For allocation */</span>
</pre></div>
</div>
<p>这些字段告诉运行时在创造这个类型的新对象时需要分配多少内存。Python为了可变长度的结构想下字符串元组有些内置支持这是 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_itemsize" title="PyTypeObject.tp_itemsize"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_itemsize</span></code></a> 字段存在的原由。这部分稍后解释。</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">tp_doc</span><span class="p">;</span>
</pre></div>
</div>
<p>这里你可以放置一段字符串或者它的地址当你想在Python脚本引用 <code class="docutils literal notranslate"><span class="pre">obj.__doc__</span></code> 时返回这段文档字符串。</p>
<p>现在我们来看一下基本类型方法 - 大多数扩展类型将实现的方法。</p>
<section id="finalization-and-de-allocation">
<h2><span class="section-number">3.1. </span>终结和内存释放<a class="headerlink" href="#finalization-and-de-allocation" title="永久链接至标题"></a></h2>
<div class="highlight-c notranslate" id="index-0"><div class="highlight"><pre><span></span><span class="n">destructor</span><span class="w"> </span><span class="n">tp_dealloc</span><span class="p">;</span>
</pre></div>
</div>
<p>当您的类型实例的引用计数减少为零并且Python解释器想要回收它时将调用此函数。如果你的类型有内存可供释放或执行其他清理你可以把它放在这里。 对象本身也需要在这里释放。 以下是此函数的示例:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">void</span>
<span class="nf">newdatatype_dealloc</span><span class="p">(</span><span class="n">newdatatypeobject</span><span class="w"> </span><span class="o">*</span><span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">free</span><span class="p">(</span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">obj_UnderlyingDatatypePtr</span><span class="p">);</span>
<span class="w"> </span><span class="n">Py_TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">tp_free</span><span class="p">(</span><span class="n">obj</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p id="index-1">一个重要的释放器函数实现要求是把所有未决异常放着不动。这很重要是因为释放器会被解释器频繁的调用,当栈异常退出时(而非正常返回)不会有任何办法保护释放器看到一个异常尚未被设置。此事释放器的任何行为都会导致额外增加的Python代码来检查异常是否被设置。这可能导致解释器的误导性错误。正确的保护方法是在任何不安全的操作前保存未决异常然后在其完成后恢复。者可以通过 <a class="reference internal" href="../c-api/exceptions.html#c.PyErr_Fetch" title="PyErr_Fetch"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyErr_Fetch()</span></code></a><a class="reference internal" href="../c-api/exceptions.html#c.PyErr_Restore" title="PyErr_Restore"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyErr_Restore()</span></code></a> 函数来实现:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">void</span>
<span class="nf">my_dealloc</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">MyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">MyObject</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">obj</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">cbresult</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">self</span><span class="o">-&gt;</span><span class="n">my_callback</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="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">err_type</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">err_value</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">err_traceback</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* This saves the current exception state */</span>
<span class="w"> </span><span class="n">PyErr_Fetch</span><span class="p">(</span><span class="o">&amp;</span><span class="n">err_type</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">err_value</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">err_traceback</span><span class="p">);</span>
<span class="w"> </span><span class="n">cbresult</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_CallObject</span><span class="p">(</span><span class="n">self</span><span class="o">-&gt;</span><span class="n">my_callback</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</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">cbresult</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="n">PyErr_WriteUnraisable</span><span class="p">(</span><span class="n">self</span><span class="o">-&gt;</span><span class="n">my_callback</span><span class="p">);</span>
<span class="w"> </span><span class="k">else</span>
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">cbresult</span><span class="p">);</span>
<span class="w"> </span><span class="cm">/* This restores the saved exception state */</span>
<span class="w"> </span><span class="n">PyErr_Restore</span><span class="p">(</span><span class="n">err_type</span><span class="p">,</span><span class="w"> </span><span class="n">err_value</span><span class="p">,</span><span class="w"> </span><span class="n">err_traceback</span><span class="p">);</span>
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="o">-&gt;</span><span class="n">my_callback</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">Py_TYPE</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">tp_free</span><span class="p">((</span><span class="n">PyObject</span><span class="o">*</span><span class="p">)</span><span class="n">self</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>你能在释放器函数中安全执行的操作是有限的。 首先,如果你的类型支持垃圾回收 (使用 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_traverse" title="PyTypeObject.tp_traverse"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_traverse</span></code></a> 和/或 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_clear" title="PyTypeObject.tp_clear"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_clear</span></code></a>),对象的部分成员可以在调用 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_dealloc" title="PyTypeObject.tp_dealloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a> 时被清空或终结。 其次,在 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_dealloc" title="PyTypeObject.tp_dealloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a> 中,你的对象将处于不稳定状态:它的引用计数等于零。 任何对非琐碎对象或 API 的调用 (如上面的示例所做的) 最终都可能会再次调用 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_dealloc" title="PyTypeObject.tp_dealloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a>,导致双重释放并发生崩溃。</p>
<p>从 Python 3.4 开始,推荐不要在 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_dealloc" title="PyTypeObject.tp_dealloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a> 放复杂的终结代码,而是使用新的 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_finalize" title="PyTypeObject.tp_finalize"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_finalize</span></code></a> 类型方法。</p>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<p><span class="target" id="index-6"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0442"><strong>PEP 442</strong></a> 解释了新的终结方案。</p>
</div>
</div>
</section>
<section id="object-presentation">
<span id="index-3"></span><h2><span class="section-number">3.2. </span>对象展示<a class="headerlink" href="#object-presentation" title="永久链接至标题"></a></h2>
<p>在 Python 中,有两种方式可以生成对象的文本表示: <a class="reference internal" href="../library/functions.html#repr" title="repr"><code class="xref py py-func docutils literal notranslate"><span class="pre">repr()</span></code></a> 函数和 <a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-func docutils literal notranslate"><span class="pre">str()</span></code></a> 函数。 (<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> 函数会直接调用 <a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-func docutils literal notranslate"><span class="pre">str()</span></code></a>。) 这些处理程序都是可选的。</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">reprfunc</span><span class="w"> </span><span class="n">tp_repr</span><span class="p">;</span>
<span class="n">reprfunc</span><span class="w"> </span><span class="n">tp_str</span><span class="p">;</span>
</pre></div>
</div>
<p><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_repr" title="PyTypeObject.tp_repr"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_repr</span></code></a> 处理程序应该返回一个字符串对象,其中包含调用它的实例的表示形式。 下面是一个简单的例子:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span>
<span class="nf">newdatatype_repr</span><span class="p">(</span><span class="n">newdatatypeobject</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">PyUnicode_FromFormat</span><span class="p">(</span><span class="s">&quot;Repr-ified_newdatatype{{size:%d}}&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">obj_UnderlyingDatatypePtr</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>如果没有指定 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_repr" title="PyTypeObject.tp_repr"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_repr</span></code></a> 处理程序,解释器将提供一个使用 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_name" title="PyTypeObject.tp_name"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_name</span></code></a> 的表示形式以及对象的惟一标识值。</p>
<p><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_str" title="PyTypeObject.tp_str"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_str</span></code></a> 处理器对于 <a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-func docutils literal notranslate"><span class="pre">str()</span></code></a> 就如上述的 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_repr" title="PyTypeObject.tp_repr"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_repr</span></code></a> 处理器对于 <a class="reference internal" href="../library/functions.html#repr" title="repr"><code class="xref py py-func docutils literal notranslate"><span class="pre">repr()</span></code></a> 一样;也就是说,它会在当 Python 代码在你的对象的某个实例上调用 <a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-func docutils literal notranslate"><span class="pre">str()</span></code></a> 时被调用。 它的实现与 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_repr" title="PyTypeObject.tp_repr"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_repr</span></code></a> 函数非常相似,但其结果字符串是供人类查看的。 如果未指定 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_str" title="PyTypeObject.tp_str"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_str</span></code></a>,则会使用 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_repr" title="PyTypeObject.tp_repr"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_repr</span></code></a> 处理器来代替。</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">PyObject</span><span class="w"> </span><span class="o">*</span>
<span class="nf">newdatatype_str</span><span class="p">(</span><span class="n">newdatatypeobject</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">PyUnicode_FromFormat</span><span class="p">(</span><span class="s">&quot;Stringified_newdatatype{{size:%d}}&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">obj_UnderlyingDatatypePtr</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
</section>
<section id="attribute-management">
<h2><span class="section-number">3.3. </span>属性管理<a class="headerlink" href="#attribute-management" title="永久链接至标题"></a></h2>
<p>对于每个可支持属性操作的对象,相应的类型必须提供用于控制属性获取方式的函数。 需要有一个能够检索属性的函数(如果定义了任何属性)还要有另一个函数负责设置属性(如果允许设置属性)。 移除属性是一种特殊情况,在此情况下要传给处理器的新值为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code></p>
<p>Python 支持两对属性处理器;一个支持属性操作的类型只需要实现其中一对的函数。 两者的差别在于一对接受 <code class="xref c c-type docutils literal notranslate"><span class="pre">char*</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="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">getattrfunc</span><span class="w"> </span><span class="n">tp_getattr</span><span class="p">;</span><span class="w"> </span><span class="cm">/* char * version */</span>
<span class="n">setattrfunc</span><span class="w"> </span><span class="n">tp_setattr</span><span class="p">;</span>
<span class="cm">/* ... */</span>
<span class="n">getattrofunc</span><span class="w"> </span><span class="n">tp_getattro</span><span class="p">;</span><span class="w"> </span><span class="cm">/* PyObject * version */</span>
<span class="n">setattrofunc</span><span class="w"> </span><span class="n">tp_setattro</span><span class="p">;</span>
</pre></div>
</div>
<p>如果访问一个对象的属性总是属于简单操作(这将在下文进行解释),则有一些泛用实现可被用来提供 <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> 版本的属性管理函数。 从 Python 2.2 开始对于类型专属的属性处理器的实际需要几乎已完全消失,尽管还存在着许多尚未更新为使用某种新的可选泛用机制的例子。</p>
<section id="generic-attribute-management">
<span id="id1"></span><h3><span class="section-number">3.3.1. </span>泛型属性管理<a class="headerlink" href="#generic-attribute-management" title="永久链接至标题"></a></h3>
<p>大多数扩展类型只使用 <strong>简单</strong> 属性,那么,是什么让属性变得“简单”呢?只需要满足下面几个条件:</p>
<ol class="arabic simple">
<li><p>当调用 <a class="reference internal" href="../c-api/type.html#c.PyType_Ready" title="PyType_Ready"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_Ready()</span></code></a> 时,必须知道属性的名称。</p></li>
<li><p>不需要特殊的处理来记录属性是否被查找或设置,也不需要根据值采取操作。</p></li>
</ol>
<p>请注意,此列表不对属性的值、值的计算时间或相关数据的存储方式施加任何限制。</p>
<p><a class="reference internal" href="../c-api/type.html#c.PyType_Ready" title="PyType_Ready"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_Ready()</span></code></a> 被调用时,它会使用由类型对象所引用的三个表来创建要放置到类型对象的字典中的 <a class="reference internal" href="../glossary.html#term-descriptor"><span class="xref std std-term">descriptor</span></a>。 每个描述器控制对实例对象的一个属性的访问。 每个表都是可选的;如果三个表全都为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>,则该类型的实例将只有从它们的基础类型继承来的属性,并且还应当让 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_getattro" title="PyTypeObject.tp_getattro"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_getattro</span></code></a><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_setattro" title="PyTypeObject.tp_setattro"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_setattro</span></code></a> 字段保持为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>,以允许由基础类型处理这些属性。</p>
<p>表被声明为object::类型的三个字段:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span><span class="w"> </span><span class="nc">PyMethodDef</span><span class="w"> </span><span class="o">*</span><span class="n">tp_methods</span><span class="p">;</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">PyMemberDef</span><span class="w"> </span><span class="o">*</span><span class="n">tp_members</span><span class="p">;</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">PyGetSetDef</span><span class="w"> </span><span class="o">*</span><span class="n">tp_getset</span><span class="p">;</span>
</pre></div>
</div>
<p>如果 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_methods" title="PyTypeObject.tp_methods"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_methods</span></code></a> 不为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>,则它必须指向一个由 <a class="reference internal" href="../c-api/structures.html#c.PyMethodDef" title="PyMethodDef"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyMethodDef</span></code></a> 结构体组成的数组。 表中的每个条目都是该结构体的一个实例:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">PyMethodDef</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">ml_name</span><span class="p">;</span><span class="w"> </span><span class="cm">/* method name */</span>
<span class="w"> </span><span class="n">PyCFunction</span><span class="w"> </span><span class="n">ml_meth</span><span class="p">;</span><span class="w"> </span><span class="cm">/* implementation function */</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">ml_flags</span><span class="p">;</span><span class="w"> </span><span class="cm">/* flags */</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">ml_doc</span><span class="p">;</span><span class="w"> </span><span class="cm">/* docstring */</span>
<span class="p">}</span><span class="w"> </span><span class="n">PyMethodDef</span><span class="p">;</span>
</pre></div>
</div>
<p>应当为该类型所提供的每个方法都定义一个条目;从基础类型继承来的方法不需要条目。 还需要在末尾加一个额外的条目;它是一个标记数组结束的哨兵条目。 该哨兵条目的 <code class="xref py py-attr docutils literal notranslate"><span class="pre">ml_name</span></code> 字段必须为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code></p>
<p>第二个表被用来定义要直接映射到实例中的数据的属性。 各种原始 C 类型均受到支持,并且访问方式可以为只读或读写。 表中的结构体被定义为:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">PyMemberDef</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">name</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">type</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">offset</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">flags</span><span class="p">;</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">doc</span><span class="p">;</span>
<span class="p">}</span><span class="w"> </span><span class="n">PyMemberDef</span><span class="p">;</span>
</pre></div>
</div>
<p>对于表中的每个条目,将构建一个 <a class="reference internal" href="../glossary.html#term-descriptor"><span class="xref std std-term">descriptor</span></a> 并添加到类型中使其能够从实例结构体中提取值。 <a class="reference internal" href="../library/functions.html#type" title="type"><code class="xref py py-attr docutils literal notranslate"><span class="pre">type</span></code></a> 字段应当包含在 <code class="file docutils literal notranslate"><span class="pre">structmember.h</span></code> 头文件中定义的某个类型的代码;该值将被用来确定如何将 Python 值转换为 C 值或者反之。 <code class="xref py py-attr docutils literal notranslate"><span class="pre">flags</span></code> 字段将被用来储存控制属性可以如何被访问的旗标。</p>
<p>以下标志常量定义在:file: ' structmember.h ';它们可以使用bitwise-OR组合。</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">READONLY</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">READ_RESTRICTED</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">WRITE_RESTRICTED</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">RESTRICTED</span></code></p></td>
<td><p>在受限模式下不可读,也不可写。</p></td>
</tr>
</tbody>
</table>
<p id="index-4">使用 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_members" title="PyTypeObject.tp_members"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_members</span></code></a> 表来构建用于运行时的描述器还有一个有趣的优点是任何以这种方式定义的属性都可以简单地通过在表中提供文本来设置一个相关联的文档字符串。 一个应用程序可以使用自省 API 从类对象获取描述器,并使用其 <code class="xref py py-attr docutils literal notranslate"><span class="pre">__doc__</span></code> 属性来获取文档字符串。</p>
<p><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_methods" title="PyTypeObject.tp_methods"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_methods</span></code></a> 表一样,需要有一个值为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 的哨兵条目 <code class="xref py py-attr docutils literal notranslate"><span class="pre">name</span></code></p>
</section>
<section id="type-specific-attribute-management">
<h3><span class="section-number">3.3.2. </span>类型专属的属性管理<a class="headerlink" href="#type-specific-attribute-management" title="永久链接至标题"></a></h3>
<p>为了简单起见,这里只演示 <code class="xref c c-type docutils literal notranslate"><span class="pre">char*</span></code> 版本name 形参的类型是 <code class="xref c c-type docutils literal notranslate"><span class="pre">char*</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> 风格接口之间的唯一区别。 这个示例实际上做了与上面的泛用示例相同的事情,但没有使用在 Python 2.2 中增加的泛用支持。 它解释了处理器函数是如何被调用的,因此如果你确实需要扩展它们的功能,你就会明白有什么是需要做的。</p>
<p><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_getattr" title="PyTypeObject.tp_getattr"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_getattr</span></code></a> 处理器会在对象需要查找属性时被调用。 它被调用的情况与一个类的 <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> 方法要被调用的情况相同。</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">PyObject</span><span class="w"> </span><span class="o">*</span>
<span class="nf">newdatatype_getattr</span><span class="p">(</span><span class="n">newdatatypeobject</span><span class="w"> </span><span class="o">*</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">name</span><span class="p">)</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">strcmp</span><span class="p">(</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;data&quot;</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="k">return</span><span class="w"> </span><span class="n">PyLong_FromLong</span><span class="p">(</span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">PyErr_Format</span><span class="p">(</span><span class="n">PyExc_AttributeError</span><span class="p">,</span>
<span class="w"> </span><span class="s">&quot;&#39;%.50s&#39; object has no attribute &#39;%.400s&#39;&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="n">tp</span><span class="o">-&gt;</span><span class="n">tp_name</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_setattr" title="PyTypeObject.tp_setattr"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_setattr</span></code></a> 处理器会在要调用一个类实例的 <a class="reference internal" href="../reference/datamodel.html#object.__setattr__" title="object.__setattr__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__setattr__()</span></code></a><a class="reference internal" href="../reference/datamodel.html#object.__delattr__" title="object.__delattr__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__delattr__()</span></code></a> 方法时被调用。 当一个属性应当被删除时,第三个形参将为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code>。 下面是一个简单地引发异常的例子;如果这确实是你想要的,则 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_setattr" title="PyTypeObject.tp_setattr"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_setattr</span></code></a> 处理器应当被设为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code></p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">newdatatype_setattr</span><span class="p">(</span><span class="n">newdatatypeobject</span><span class="w"> </span><span class="o">*</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">name</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">v</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">PyErr_Format</span><span class="p">(</span><span class="n">PyExc_RuntimeError</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Read-only attribute: %s&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">name</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="p">}</span>
</pre></div>
</div>
</section>
</section>
<section id="object-comparison">
<h2><span class="section-number">3.4. </span>对象比较<a class="headerlink" href="#object-comparison" title="永久链接至标题"></a></h2>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">richcmpfunc</span><span class="w"> </span><span class="n">tp_richcompare</span><span class="p">;</span>
</pre></div>
</div>
<p><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_richcompare" title="PyTypeObject.tp_richcompare"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_richcompare</span></code></a> 处理器会在需要进行比较时被调用。 它类似于 <a class="reference internal" href="../reference/datamodel.html#richcmpfuncs"><span class="std std-ref">富比较方法</span></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>,并会被 <a class="reference internal" href="../c-api/object.html#c.PyObject_RichCompare" title="PyObject_RichCompare"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_RichCompare()</span></code></a><a class="reference internal" href="../c-api/object.html#c.PyObject_RichCompareBool" title="PyObject_RichCompareBool"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_RichCompareBool()</span></code></a> 所调用。</p>
<p>这个函数将被用两个Python对象和一个运算符作为参数调用, 运算符可以是 <code class="docutils literal notranslate"><span class="pre">Py_EQ</span></code> , <code class="docutils literal notranslate"><span class="pre">Py_NE</span></code> , <code class="docutils literal notranslate"><span class="pre">Py_LE</span></code> , <code class="docutils literal notranslate"><span class="pre">Py_GT</span></code> , <code class="docutils literal notranslate"><span class="pre">Py_LT</span></code><code class="docutils literal notranslate"><span class="pre">Py_GT</span></code> 中的一个. 它将依照运算符比较两个对象并且返回 <code class="docutils literal notranslate"><span class="pre">Py_True</span></code><code class="docutils literal notranslate"><span class="pre">Py_False</span></code> 如果比较成功, <code class="docutils literal notranslate"><span class="pre">Py_NotImplemented</span></code> 表明两个对象不支持尝试的方法, <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 表明造成了一个异常</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">PyObject</span><span class="w"> </span><span class="o">*</span>
<span class="nf">newdatatype_richcmp</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">obj1</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">obj2</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">op</span><span class="p">)</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">result</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">size1</span><span class="p">,</span><span class="w"> </span><span class="n">size2</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* code to make sure that both arguments are of type</span>
<span class="cm"> newdatatype omitted */</span>
<span class="w"> </span><span class="n">size1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">obj1</span><span class="o">-&gt;</span><span class="n">obj_UnderlyingDatatypePtr</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">;</span>
<span class="w"> </span><span class="n">size2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">obj2</span><span class="o">-&gt;</span><span class="n">obj_UnderlyingDatatypePtr</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">;</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">op</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">Py_LT</span><span class="p">:</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">size1</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">size2</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">Py_LE</span><span class="p">:</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">size1</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">size2</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">Py_EQ</span><span class="p">:</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">size1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">size2</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">Py_NE</span><span class="p">:</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">size1</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">size2</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">Py_GT</span><span class="p">:</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">size1</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">size2</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">Py_GE</span><span class="p">:</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">size1</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">size2</span><span class="p">;</span><span class="w"> </span><span class="k">break</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="n">Py_True</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">Py_False</span><span class="p">;</span>
<span class="w"> </span><span class="n">Py_INCREF</span><span class="p">(</span><span class="n">result</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">result</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
</pre></div>
</div>
</section>
<section id="abstract-protocol-support">
<h2><span class="section-number">3.5. </span>抽象协议支持<a class="headerlink" href="#abstract-protocol-support" title="永久链接至标题"></a></h2>
<p>Python 支持多种 <em>抽象</em> '协议';被提供来使用这些接口的专门接口说明请在 <a class="reference internal" href="../c-api/abstract.html#abstract"><span class="std std-ref">抽象对象层</span></a> 中查看。</p>
<p>这些抽象接口很多都是在 Python 实现开发的早期被定义的。 特别地,数字、映射和序列协议从一开始就已经是 Python 的组成部分。 其他协议则是后来添加的。 对于依赖某些来自类型实现的处理器例程的协议来说,较旧的协议被定义为类型对象所引用的处理器的可选块。 对于较新的协议来说在主类型对象中还有额外的槽位,并带有一个预设旗标位来指明存在该槽位并应当由解释器来检查。 (此旗标位并不会指明槽位值非 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 的情况,可以设置该旗标来指明一个槽位的存在,但此本位仍可能保持未填充的状态。)</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyNumberMethods</span><span class="w"> </span><span class="o">*</span><span class="n">tp_as_number</span><span class="p">;</span>
<span class="n">PySequenceMethods</span><span class="w"> </span><span class="o">*</span><span class="n">tp_as_sequence</span><span class="p">;</span>
<span class="n">PyMappingMethods</span><span class="w"> </span><span class="o">*</span><span class="n">tp_as_mapping</span><span class="p">;</span>
</pre></div>
</div>
<p>如果你希望你的对象的行为类似一个数字、序列或映射对象,那么你就要分别放置一个实现了 C 类型 <a class="reference internal" href="../c-api/typeobj.html#c.PyNumberMethods" title="PyNumberMethods"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyNumberMethods</span></code></a>, <a class="reference internal" href="../c-api/typeobj.html#c.PySequenceMethods" title="PySequenceMethods"><code class="xref c c-type docutils literal notranslate"><span class="pre">PySequenceMethods</span></code></a><a class="reference internal" href="../c-api/typeobj.html#c.PyMappingMethods" title="PyMappingMethods"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyMappingMethods</span></code></a>, 的结构体的地址。 你要负责将适当的值填入这些结构体。 你可以在 Python 源代码发布版的 <code class="file docutils literal notranslate"><span class="pre">Objects</span></code> 目录中找到这些对象各自的用法示例。</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">hashfunc</span><span class="w"> </span><span class="n">tp_hash</span><span class="p">;</span>
</pre></div>
</div>
<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">Py_hash_t</span>
<span class="nf">newdatatype_hash</span><span class="p">(</span><span class="n">newdatatypeobject</span><span class="w"> </span><span class="o">*</span><span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">Py_hash_t</span><span class="w"> </span><span class="n">result</span><span class="p">;</span>
<span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">some_size</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">32767</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">some_number</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">result</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="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">-2</span><span class="p">;</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="xref c c-type docutils literal notranslate"><span class="pre">Py_hash_t</span></code> 是一个在宽度取决于具体平台的有符号整数类型。 从 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_hash" title="PyTypeObject.tp_hash"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_hash</span></code></a> 返回 <code class="docutils literal notranslate"><span class="pre">-1</span></code> 表示发生了错误,这就是为什么你应当注意避免在哈希运算成功时返回它,如上面所演示的。</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">ternaryfunc</span><span class="w"> </span><span class="n">tp_call</span><span class="p">;</span>
</pre></div>
</div>
<p>此函数会在“调用”你的数据类型实例时被调用,举例来说,如果 <code class="docutils literal notranslate"><span class="pre">obj1</span></code> 是你的数据类型的实例而 Python 脚本包含了 <code class="docutils literal notranslate"><span class="pre">obj1('hello')</span></code>,则将发起调用 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_call" title="PyTypeObject.tp_call"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_call</span></code></a> 处理器。</p>
<p>此函数接受三个参数:</p>
<ol class="arabic simple">
<li><p><em>self</em> 是作为调用目标的数据类型实例。 如果调用是 <code class="docutils literal notranslate"><span class="pre">obj1('hello')</span></code>,则 <em>self</em><code class="docutils literal notranslate"><span class="pre">obj1</span></code></p></li>
<li><p><em>args</em> 是包含调用参数的元组。 你可以使用 <a class="reference internal" href="../c-api/arg.html#c.PyArg_ParseTuple" title="PyArg_ParseTuple"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyArg_ParseTuple()</span></code></a> 来提取参数。</p></li>
<li><p><em>kwds</em> 是由传入的关键字参数组成的字典。 如果它不为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> 且你支持关键字参数,则可使用 <a class="reference internal" href="../c-api/arg.html#c.PyArg_ParseTupleAndKeywords" title="PyArg_ParseTupleAndKeywords"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyArg_ParseTupleAndKeywords()</span></code></a> 来提取参数。 如果你不想支持关键字参数而它为非 <code class="docutils literal notranslate"><span class="pre">NULL</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></li>
</ol>
<p>下面是一个演示性的 <code class="docutils literal notranslate"><span class="pre">tp_call</span></code> 实现:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span>
<span class="nf">newdatatype_call</span><span class="p">(</span><span class="n">newdatatypeobject</span><span class="w"> </span><span class="o">*</span><span class="n">self</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">args</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">kwds</span><span class="p">)</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">result</span><span class="p">;</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">arg1</span><span class="p">;</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">arg2</span><span class="p">;</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">arg3</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">PyArg_ParseTuple</span><span class="p">(</span><span class="n">args</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;sss:call&quot;</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">arg1</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">arg2</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">arg3</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="nb">NULL</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyUnicode_FromFormat</span><span class="p">(</span>
<span class="w"> </span><span class="s">&quot;Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">obj_UnderlyingDatatypePtr</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">,</span>
<span class="w"> </span><span class="n">arg1</span><span class="p">,</span><span class="w"> </span><span class="n">arg2</span><span class="p">,</span><span class="w"> </span><span class="n">arg3</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/* Iterators */</span>
<span class="n">getiterfunc</span><span class="w"> </span><span class="n">tp_iter</span><span class="p">;</span>
<span class="n">iternextfunc</span><span class="w"> </span><span class="n">tp_iternext</span><span class="p">;</span>
</pre></div>
</div>
<p>这些函数提供了对迭代器协议的支持。 两个处理器都只接受一个形参,即它们被调用时所使用的实例,并返回一个新的引用。 当发生错误时,它们应当设置一个异常并返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iter" title="PyTypeObject.tp_iter"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iter</span></code></a> 对应于 Python <a class="reference internal" href="../reference/datamodel.html#object.__iter__" title="object.__iter__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__iter__()</span></code></a> 方法,而 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iternext" title="PyTypeObject.tp_iternext"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iternext</span></code></a> 对应于 Python <a class="reference internal" href="../library/stdtypes.html#iterator.__next__" title="iterator.__next__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__next__()</span></code></a> 方法。</p>
<p>任何 <a class="reference internal" href="../glossary.html#term-iterable"><span class="xref std std-term">iterable</span></a> 对象都必须实现 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iter" title="PyTypeObject.tp_iter"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iter</span></code></a> 处理器,该处理器必须返回一个 <a class="reference internal" href="../glossary.html#term-iterator"><span class="xref std std-term">iterator</span></a> 对象。 下面是与 Python 类所应用的同一个指导原则:</p>
<ul class="simple">
<li><p>对于可以支持多个独立迭代器的多项集(如列表和元组),则应当在每次调用 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iter" title="PyTypeObject.tp_iter"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iter</span></code></a> 时创建并返回一个新的迭代器。</p></li>
<li><p>只能被迭代一次的对象(通常是由于迭代操作的附带影响,例如文件对象)可以通过返回一个指向自身的新引用来实现 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iter" title="PyTypeObject.tp_iter"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iter</span></code></a> -- 并且为此还应当实现 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iternext" title="PyTypeObject.tp_iternext"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iternext</span></code></a> 处理器。</p></li>
</ul>
<p>任何 <a class="reference internal" href="../glossary.html#term-iterator"><span class="xref std std-term">iterator</span></a> 对象都应当同时实现 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iter" title="PyTypeObject.tp_iter"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iter</span></code></a><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iternext" title="PyTypeObject.tp_iternext"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iternext</span></code></a>。 一个迭代器的 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iter" title="PyTypeObject.tp_iter"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iter</span></code></a> 处理器应当返回一个指向该迭代器的新引用。 它的 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iternext" title="PyTypeObject.tp_iternext"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iternext</span></code></a> 处理器应当返回一个指向迭代操作的下一个对象的新引用,如果还有下一个对象的话。 如果迭代已到达末尾,则 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iternext" title="PyTypeObject.tp_iternext"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iternext</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> 的基础上 <em>额外</em> 设置 <a class="reference internal" href="../library/exceptions.html#StopIteration" title="StopIteration"><code class="xref py py-exc docutils literal notranslate"><span class="pre">StopIteration</span></code></a>;避免异常可以产生更好的性能。 如果发生了实际的错误,则 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_iternext" title="PyTypeObject.tp_iternext"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_iternext</span></code></a> 应当总是设置一个异常并返回 <code class="docutils literal notranslate"><span class="pre">NULL</span></code></p>
</section>
<section id="weak-reference-support">
<span id="weakref-support"></span><h2><span class="section-number">3.6. </span>弱引用支持<a class="headerlink" href="#weak-reference-support" title="永久链接至标题"></a></h2>
<p>One of the goals of Python 弱引用实现的目标之一是允许任意类型参与弱引用机制而不会在重视性能的对象(例如数字)上产生额外开销。</p>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<p><a class="reference internal" href="../library/weakref.html#module-weakref" title="weakref: Support for weak references and weak dictionaries."><code class="xref py py-mod docutils literal notranslate"><span class="pre">weakref</span></code></a> 模块的文档。</p>
</div>
<p>对于可弱引用的对象,扩展类型必须做两件事:</p>
<ol class="arabic simple">
<li><p>在 C 对象结构体中包括一个专门用于弱引用机制的 <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> 字段。 该对象的构造器应当让它保持为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code> (当使用默认的 <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_alloc" title="PyTypeObject.tp_alloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_alloc</span></code></a> 时这将会自动设置)。</p></li>
<li><p><a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_weaklistoffset" title="PyTypeObject.tp_weaklistoffset"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_weaklistoffset</span></code></a> 类型成员设置为 C 对象结构体中上述字段的偏移量,这样解释器就能知道如何访问和修改该字段。</p></li>
</ol>
<p>具体来说,下面是一个微小的对象结构体如何被增强为具有所需的字段:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PyObject_HEAD</span>
<span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">weakreflist</span><span class="p">;</span><span class="w"> </span><span class="cm">/* List of weak references */</span>
<span class="p">}</span><span class="w"> </span><span class="n">TrivialObject</span><span class="p">;</span>
</pre></div>
</div>
<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">PyTypeObject</span><span class="w"> </span><span class="n">TrivialType</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PyVarObject_HEAD_INIT</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
<span class="w"> </span><span class="cm">/* ... other members omitted for brevity ... */</span>
<span class="w"> </span><span class="p">.</span><span class="n">tp_weaklistoffset</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">offsetof</span><span class="p">(</span><span class="n">TrivialObject</span><span class="p">,</span><span class="w"> </span><span class="n">weakreflist</span><span class="p">),</span>
<span class="p">};</span>
</pre></div>
</div>
<p>唯一的额外补充是如果字段不为 <code class="docutils literal notranslate"><span class="pre">NULL</span></code><code class="docutils literal notranslate"><span class="pre">tp_dealloc</span></code> 需要清除任何弱引用 (通过调用 <code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_ClearWeakRefs()</span></code>)。:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">void</span>
<span class="nf">Trivial_dealloc</span><span class="p">(</span><span class="n">TrivialObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="cm">/* Clear weakrefs first before calling any destructors */</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">self</span><span class="o">-&gt;</span><span class="n">weakreflist</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="n">PyObject_ClearWeakRefs</span><span class="p">((</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">self</span><span class="p">);</span>
<span class="w"> </span><span class="cm">/* ... remainder of destruction code omitted for brevity ... */</span>
<span class="w"> </span><span class="n">Py_TYPE</span><span class="p">(</span><span class="n">self</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">tp_free</span><span class="p">((</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">self</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
</section>
<section id="more-suggestions">
<h2><span class="section-number">3.7. </span>更多建议<a class="headerlink" href="#more-suggestions" title="永久链接至标题"></a></h2>
<p>为了学习如何为你的新数据类型实现任何特定方法,请获取 <a class="reference internal" href="../glossary.html#term-cpython"><span class="xref std std-term">CPython</span></a> 源代码。 进入 <code class="file docutils literal notranslate"><span class="pre">Objects</span></code> 目录,然后在 C 源文件中搜索 <code class="docutils literal notranslate"><span class="pre">tp_</span></code> 加上你想要的函数 (例如,<code class="docutils literal notranslate"><span class="pre">tp_richcompare</span></code>)。 你将找到你想要实现的函数的例子。</p>
<p>当你需要验证一个对象是否为你实现的类型的具体实例时,请使用 <a class="reference internal" href="../c-api/object.html#c.PyObject_TypeCheck" title="PyObject_TypeCheck"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_TypeCheck()</span></code></a> 函数。 它的一个用法示例如下:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">PyObject_TypeCheck</span><span class="p">(</span><span class="n">some_object</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">MyType</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;arg #1 not a mything&quot;</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<div class="admonition seealso">
<p class="admonition-title">参见</p>
<dl class="simple">
<dt>下载CPython源代码版本。</dt><dd><p><a class="reference external" href="https://www.python.org/downloads/source/">https://www.python.org/downloads/source/</a></p>
</dd>
<dt>GitHub上开发CPython源代码的CPython项目。</dt><dd><p><a class="reference external" href="https://github.com/python/cpython">https://github.com/python/cpython</a></p>
</dd>
</dl>
</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="#">3. 定义扩展类型:已分类主题</a><ul>
<li><a class="reference internal" href="#finalization-and-de-allocation">3.1. 终结和内存释放</a></li>
<li><a class="reference internal" href="#object-presentation">3.2. 对象展示</a></li>
<li><a class="reference internal" href="#attribute-management">3.3. 属性管理</a><ul>
<li><a class="reference internal" href="#generic-attribute-management">3.3.1. 泛型属性管理</a></li>
<li><a class="reference internal" href="#type-specific-attribute-management">3.3.2. 类型专属的属性管理</a></li>
</ul>
</li>
<li><a class="reference internal" href="#object-comparison">3.4. 对象比较</a></li>
<li><a class="reference internal" href="#abstract-protocol-support">3.5. 抽象协议支持</a></li>
<li><a class="reference internal" href="#weak-reference-support">3.6. 弱引用支持</a></li>
<li><a class="reference internal" href="#more-suggestions">3.7. 更多建议</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="newtypes_tutorial.html"
title="上一章"><span class="section-number">2. </span>自定义扩展类型:教程</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="building.html"
title="下一章"><span class="section-number">4. </span>构建C/C++扩展</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/extending/newtypes.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="building.html" title="4. 构建C/C++扩展"
>下一页</a> |</li>
<li class="right" >
<a href="newtypes_tutorial.html" title="2. 自定义扩展类型:教程"
>上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >扩展和嵌入 Python 解释器</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="footer">
&copy; <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
<br />
This page is licensed under the Python Software Foundation License Version 2.
<br />
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
<br />
<br />
The Python Software Foundation is a non-profit corporation.
<a href="https://www.python.org/psf/donations/">Please donate.</a>
<br />
<br />
最后更新于 12月 09, 2024.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,305 @@
<!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>5. 在Windows平台编译C和C++扩展 &#8212; Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<script src="../_static/translations.js"></script>
<script src="../_static/sidebar.js"></script>
<link rel="search" type="application/opensearchdescription+xml"
title="在 Python 3.8.20 文档 中搜索"
href="../_static/opensearch.xml"/>
<link rel="author" title="关于这些文档" href="../about.html" />
<link rel="index" title="索引" href="../genindex.html" />
<link rel="search" title="搜索" href="../search.html" />
<link rel="copyright" title="版权所有" href="../copyright.html" />
<link rel="next" title="1. 在其它应用程序嵌入 Python" href="embedding.html" />
<link rel="prev" title="4. 构建C/C++扩展" href="building.html" />
<link rel="canonical" href="https://docs.python.org/3/extending/windows.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="#">5. 在Windows平台编译C和C++扩展</a><ul>
<li><a class="reference internal" href="#a-cookbook-approach">5.1. 菜谱式说明</a></li>
<li><a class="reference internal" href="#differences-between-unix-and-windows">5.2. Unix 和 Windows 之间的差异</a></li>
<li><a class="reference internal" href="#using-dlls-in-practice">5.3. DLL 的实际使用</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="building.html"
title="上一章"><span class="section-number">4. </span>构建C/C++扩展</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="embedding.html"
title="下一章"><span class="section-number">1. </span>在其它应用程序嵌入 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/extending/windows.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/extending/windows.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="embedding.html" title="1. 在其它应用程序嵌入 Python"
accesskey="N">下一页</a> |</li>
<li class="right" >
<a href="building.html" title="4. 构建C/C++扩展"
accesskey="P">上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">扩展和嵌入 Python 解释器</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="building-c-and-c-extensions-on-windows">
<span id="building-on-windows"></span><h1><span class="section-number">5. </span>在Windows平台编译C和C++扩展<a class="headerlink" href="#building-c-and-c-extensions-on-windows" title="永久链接至标题"></a></h1>
<p>这一章简要介绍了如何使用 Microsoft Visual C++ 创建 Python 的 Windows 扩展模块,然后再提供有关其工作机理的详细背景信息。 这些说明材料同时适用于 Windows 程序员学习构建 Python 扩展以及 Unix 程序员学习如何生成在 Unix 和 Windows 上均能成功构建的软件。</p>
<p>鼓励模块作者使用 distutils 方式来构建扩展模块,而不使用本节所描述的方式。 你仍将需要使用 C 编译器来构建 Python通常为 Microsoft Visual C++。</p>
<div class="admonition note">
<p class="admonition-title">注解</p>
<p>这一章提及了多个包括已编码 Python 版本号的文件名。 这些文件名以显示为 <code class="docutils literal notranslate"><span class="pre">XY</span></code> 的版本号来代表;在实践中,<code class="docutils literal notranslate"><span class="pre">'X'</span></code> 将为你所使用的 Python 发布版的主版本号而 <code class="docutils literal notranslate"><span class="pre">'Y'</span></code> 将为次版本号。 例如,如果你所使用的是 Python 2.2.1<code class="docutils literal notranslate"><span class="pre">XY</span></code> 将为 <code class="docutils literal notranslate"><span class="pre">22</span></code></p>
</div>
<section id="a-cookbook-approach">
<span id="win-cookbook"></span><h2><span class="section-number">5.1. </span>菜谱式说明<a class="headerlink" href="#a-cookbook-approach" title="永久链接至标题"></a></h2>
<p>在 Windows 和 Unix 上构建扩展模块都有两种方式:使用 <a class="reference internal" href="../library/distutils.html#module-distutils" title="distutils: Support for building and installing Python modules into an existing Python installation."><code class="xref py py-mod docutils literal notranslate"><span class="pre">distutils</span></code></a> 包来控制构建过程,或者全手动操作。 distutils 方式适用于大多数扩展;使用 <a class="reference internal" href="../library/distutils.html#module-distutils" title="distutils: Support for building and installing Python modules into an existing Python installation."><code class="xref py py-mod docutils literal notranslate"><span class="pre">distutils</span></code></a> 构建和打包扩展模块的文档见 <a class="reference internal" href="../distutils/index.html#distutils-index"><span class="std std-ref">分发 Python 模块(遗留版本)</span></a>。 如果你发现你确实需要手动操作,那么研究一下 <a class="reference external" href="https://github.com/python/cpython/tree/3.8/PCbuild/winsound.vcxproj">winsound</a> 标准库模块的项目文件可能会很有帮助。</p>
</section>
<section id="differences-between-unix-and-windows">
<span id="dynamic-linking"></span><h2><span class="section-number">5.2. </span>Unix 和 Windows 之间的差异<a class="headerlink" href="#differences-between-unix-and-windows" title="永久链接至标题"></a></h2>
<p>Unix 和 Windows 对于代码的运行时加载使用了完全不同的范式。 在你尝试构建可动态加载的模块之前,要先了解你所用系统是如何工作的。</p>
<p>在 Unix 中,一个共享对象 (<code class="file docutils literal notranslate"><span class="pre">.so</span></code>) 文件中包含将由程序来使用的代码,也包含在程序中可被找到的函数名称和数据。 当文件被合并到程序中时,对在文件代码中这些函数和数据的全部引用都会被改为指向程序中函数和数据在内存中所放置的实际位置。 这基本上是一个链接操作。</p>
<p>在 Windows 中,一个动态链接库 (<code class="file docutils literal notranslate"><span class="pre">.dll</span></code>) 文件中没有悬挂的引用。 而是通过一个查找表执行对函数或数据的访问。 因此在运行时 DLL 代码不必在运行时进行修改;相反地,代码已经使用了 DLL 的查找表,并且在运行时查找表会被修改以指向特定的函数和数据。</p>
<p>在 Unix 中,只存在一种库文件 (<code class="file docutils literal notranslate"><span class="pre">.a</span></code>),它包含来自多个对象文件 (<code class="file docutils literal notranslate"><span class="pre">.o</span></code>) 的代码。 在创建共享对象文件 (<code class="file docutils literal notranslate"><span class="pre">.so</span></code>) 的链接阶段,链接器可能会发现它不知道某个标识符是在哪里定义的。 链接器将在各个库的对象文件中查找它;如果找到了它,链接器将会包括来自该对象文件的所有代码。</p>
<p>在 Windows 中,存在两种库类型,静态库和导入库 (扩展名都是 <code class="file docutils literal notranslate"><span class="pre">.lib</span></code>)。 静态库类似于 Unix 的 <code class="file docutils literal notranslate"><span class="pre">.a</span></code> 文件;它包含在必要时可被包括的代码。 导入库基本上仅用于让链接器能确保特定标识符是合法的,并且将在 DLL 被加载时出现于程序中。 这样链接器可使用来自导入库的信息构建查找表以便使用未包括在 DLL 中的标识符。 当一个应用程序或 DLL 被链接时,可能会生成一个导入库,它将需要被用于应用程序或 DLL 中未来所有依赖于这些符号的 DLL。</p>
<p>假设你正在编译两个动态加载模块 B 和 C它们应当共享另一个代码块 A。 在 Unix 上,你 <em>不应</em><code class="file docutils literal notranslate"><span class="pre">A.a</span></code> 传给链接器作为 <code class="file docutils literal notranslate"><span class="pre">B.so</span></code><code class="file docutils literal notranslate"><span class="pre">C.so</span></code>;那会导致它被包括两次,这样 B 和 C 将分别拥有它们自己的副本。 在 Windows 上,编译 <code class="file docutils literal notranslate"><span class="pre">A.dll</span></code> 将同时编译 <code class="file docutils literal notranslate"><span class="pre">A.lib</span></code>。 你 <em>应当</em><code class="file docutils literal notranslate"><span class="pre">A.lib</span></code> 传给链接器用于 B 和 C。 <code class="file docutils literal notranslate"><span class="pre">A.lib</span></code> 并不包含代码;它只包含将在运行时被用于访问 A 的代码的信息。</p>
<p>在 Windows 上,使用导入库有点像是使用 <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">spam</span></code>;它让你可以访问 spam 中的名称,但并不会创建一个单独副本。 在 Unix 上,链接到一个库更像是 <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">spam</span> <span class="pre">import</span> <span class="pre">*</span></code>;它会创建一个单独副本。</p>
</section>
<section id="using-dlls-in-practice">
<span id="win-dlls"></span><h2><span class="section-number">5.3. </span>DLL 的实际使用<a class="headerlink" href="#using-dlls-in-practice" title="永久链接至标题"></a></h2>
<p>Windows 版 Python 是用 Microsoft Visual C++ 编译的;使用其他编译器可能行也可能不行(但 Borland 看来是可以的)。 这一节的剩余部分只适用于 MSVC++。</p>
<p>当在 Windows 中创建 DLL 时,你必须将 <code class="file docutils literal notranslate"><span class="pre">pythonXY.lib</span></code> 传给链接器。 要编译两个 DLLspam 和 ni (会使用 spam 中找到的 C 函数),你应当使用以下命令:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">cl</span><span class="w"> </span><span class="o">/</span><span class="n">LD</span><span class="w"> </span><span class="o">/</span><span class="n">I</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">include</span><span class="w"> </span><span class="n">spam</span><span class="p">.</span><span class="n">c</span><span class="w"> </span><span class="p">..</span><span class="o">/</span><span class="n">libs</span><span class="o">/</span><span class="n">pythonXY</span><span class="p">.</span><span class="n">lib</span>
<span class="n">cl</span><span class="w"> </span><span class="o">/</span><span class="n">LD</span><span class="w"> </span><span class="o">/</span><span class="n">I</span><span class="o">/</span><span class="n">python</span><span class="o">/</span><span class="n">include</span><span class="w"> </span><span class="n">ni</span><span class="p">.</span><span class="n">c</span><span class="w"> </span><span class="n">spam</span><span class="p">.</span><span class="n">lib</span><span class="w"> </span><span class="p">..</span><span class="o">/</span><span class="n">libs</span><span class="o">/</span><span class="n">pythonXY</span><span class="p">.</span><span class="n">lib</span>
</pre></div>
</div>
<p>第一个命令创建了三个文件: <code class="file docutils literal notranslate"><span class="pre">spam.obj</span></code>, <code class="file docutils literal notranslate"><span class="pre">spam.dll</span></code><code class="file docutils literal notranslate"><span class="pre">spam.lib</span></code><code class="file docutils literal notranslate"><span class="pre">Spam.dll</span></code> 不包含任何 Python 函数 (例如 <a class="reference internal" href="../c-api/arg.html#c.PyArg_ParseTuple" title="PyArg_ParseTuple"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyArg_ParseTuple()</span></code></a>),但它通过 <code class="file docutils literal notranslate"><span class="pre">pythonXY.lib</span></code> 可以知道如何找到所需的 Python 代码。</p>
<p>第二条命令创建了 <code class="file docutils literal notranslate"><span class="pre">ni.dll</span></code> (以及 <code class="file docutils literal notranslate"><span class="pre">.obj</span></code><code class="file docutils literal notranslate"><span class="pre">.lib</span></code>),它知道如何从 spam 以及 Python 可执行文件中找到所需的函数。</p>
<p>不是每个标识符都会被导出到查找表。 如果你想要任何其他模块(包括 Python都能看到你的标识符你必须写上 <code class="docutils literal notranslate"><span class="pre">_declspec(dllexport)</span></code>,就如在 <code class="docutils literal notranslate"><span class="pre">void</span> <span class="pre">_declspec(dllexport)</span> <span class="pre">initspam(void)</span></code><code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">_declspec(dllexport)</span> <span class="pre">*NiGetSpamData(void)</span></code> 中一样。</p>
<p>Developer Studio 将加入大量你并不真正需要的导入库,使你的可执行文件大小增加 100K。 要摆脱它们,请使用项目设置对话框的链接选项卡指定 <em>忽略默认库</em>。 将正确的 <code class="file docutils literal notranslate"><span class="pre">msvcrtxx.lib</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="#">5. 在Windows平台编译C和C++扩展</a><ul>
<li><a class="reference internal" href="#a-cookbook-approach">5.1. 菜谱式说明</a></li>
<li><a class="reference internal" href="#differences-between-unix-and-windows">5.2. Unix 和 Windows 之间的差异</a></li>
<li><a class="reference internal" href="#using-dlls-in-practice">5.3. DLL 的实际使用</a></li>
</ul>
</li>
</ul>
<h4>上一个主题</h4>
<p class="topless"><a href="building.html"
title="上一章"><span class="section-number">4. </span>构建C/C++扩展</a></p>
<h4>下一个主题</h4>
<p class="topless"><a href="embedding.html"
title="下一章"><span class="section-number">1. </span>在其它应用程序嵌入 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/extending/windows.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="embedding.html" title="1. 在其它应用程序嵌入 Python"
>下一页</a> |</li>
<li class="right" >
<a href="building.html" title="4. 构建C/C++扩展"
>上一页</a> |</li>
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
<li><a href="https://www.python.org/">Python</a> &#187;</li>
<li class="switchers">
<div class="language_switcher_placeholder"></div>
<div class="version_switcher_placeholder"></div>
</li>
<li>
</li>
<li id="cpython-language-and-version">
<a href="../index.html">3.8.20 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >扩展和嵌入 Python 解释器</a> &#187;</li>
<li class="right">
<div class="inline-search" role="search">
<form class="inline-search" action="../search.html" method="get">
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
<input type="submit" value="转向" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
|
</li>
</ul>
</div>
<div class="footer">
&copy; <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
<br />
This page is licensed under the Python Software Foundation License Version 2.
<br />
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
<br />
<br />
The Python Software Foundation is a non-profit corporation.
<a href="https://www.python.org/psf/donations/">Please donate.</a>
<br />
<br />
最后更新于 12月 09, 2024.
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
<br />
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
</div>
</body>
</html>