718 lines
82 KiB
HTML
718 lines
82 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_CN">
|
||
<head>
|
||
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||
|
||
<title>设计和历史常见问题 — Python 3.8.20 文档</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
||
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||
|
||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||
<script src="../_static/jquery.js"></script>
|
||
<script src="../_static/underscore.js"></script>
|
||
<script src="../_static/doctools.js"></script>
|
||
<script src="../_static/language_data.js"></script>
|
||
<script src="../_static/translations.js"></script>
|
||
|
||
<script src="../_static/sidebar.js"></script>
|
||
|
||
<link rel="search" type="application/opensearchdescription+xml"
|
||
title="在 Python 3.8.20 文档 中搜索"
|
||
href="../_static/opensearch.xml"/>
|
||
<link rel="author" title="关于这些文档" href="../about.html" />
|
||
<link rel="index" title="索引" href="../genindex.html" />
|
||
<link rel="search" title="搜索" href="../search.html" />
|
||
<link rel="copyright" title="版权所有" href="../copyright.html" />
|
||
<link rel="next" title="代码库和插件 FAQ" href="library.html" />
|
||
<link rel="prev" title="编程常见问题" href="programming.html" />
|
||
<link rel="canonical" href="https://docs.python.org/3/faq/design.html" />
|
||
|
||
|
||
|
||
|
||
|
||
<style>
|
||
@media only screen {
|
||
table.full-width-table {
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style>
|
||
<link rel="shortcut icon" type="image/png" href="../_static/py.svg" />
|
||
<script type="text/javascript" src="../_static/copybutton.js"></script>
|
||
<script type="text/javascript" src="../_static/menu.js"></script>
|
||
|
||
</head>
|
||
<body>
|
||
<div class="mobile-nav">
|
||
<input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
|
||
aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu" />
|
||
<label for="menuToggler" class="toggler__label">
|
||
<span></span>
|
||
</label>
|
||
<nav class="nav-content" role="navigation">
|
||
<a href="https://www.python.org/" class="nav-logo">
|
||
<img src="../_static/py.svg" alt="Logo"/>
|
||
</a>
|
||
<div class="version_switcher_placeholder"></div>
|
||
<form role="search" class="search" action="../search.html" method="get">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
|
||
<path fill-rule="nonzero"
|
||
d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" fill="#444"></path>
|
||
</svg>
|
||
<input type="text" name="q" aria-label="快速搜索"/>
|
||
<input type="submit" value="转向"/>
|
||
</form>
|
||
</nav>
|
||
<div class="menu-wrapper">
|
||
<nav class="menu" role="navigation" aria-label="main navigation">
|
||
<div class="language_switcher_placeholder"></div>
|
||
<h3><a href="../contents.html">目录</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">设计和历史常见问题</a><ul>
|
||
<li><a class="reference internal" href="#why-does-python-use-indentation-for-grouping-of-statements">为什么 Python 使用缩进来分组语句?</a></li>
|
||
<li><a class="reference internal" href="#why-am-i-getting-strange-results-with-simple-arithmetic-operations">为什么简单的算术运算得到奇怪的结果?</a></li>
|
||
<li><a class="reference internal" href="#why-are-floating-point-calculations-so-inaccurate">为什么浮点计算不准确?</a></li>
|
||
<li><a class="reference internal" href="#why-are-python-strings-immutable">为什么Python字符串是不可变的?</a></li>
|
||
<li><a class="reference internal" href="#why-must-self-be-used-explicitly-in-method-definitions-and-calls">为什么必须在方法定义和调用中显式使用“self”?</a></li>
|
||
<li><a class="reference internal" href="#why-can-t-i-use-an-assignment-in-an-expression">为什么不能在表达式中赋值?</a></li>
|
||
<li><a class="reference internal" href="#why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list">为什么Python对某些功能(例如list.index())使用方法来实现,而其他功能(例如len(List))使用函数实现?</a></li>
|
||
<li><a class="reference internal" href="#why-is-join-a-string-method-instead-of-a-list-or-tuple-method">为什么 join() 是一个字符串方法而不是列表或元组方法?</a></li>
|
||
<li><a class="reference internal" href="#how-fast-are-exceptions">异常有多快?</a></li>
|
||
<li><a class="reference internal" href="#why-isn-t-there-a-switch-or-case-statement-in-python">为什么Python中没有switch或case语句?</a></li>
|
||
<li><a class="reference internal" href="#can-t-you-emulate-threads-in-the-interpreter-instead-of-relying-on-an-os-specific-thread-implementation">难道不能在解释器中模拟线程,而非得依赖特定于操作系统的线程实现吗?</a></li>
|
||
<li><a class="reference internal" href="#why-can-t-lambda-expressions-contain-statements">为什么lambda表达式不能包含语句?</a></li>
|
||
<li><a class="reference internal" href="#can-python-be-compiled-to-machine-code-c-or-some-other-language">可以将Python编译为机器代码,C或其他语言吗?</a></li>
|
||
<li><a class="reference internal" href="#how-does-python-manage-memory">Python如何管理内存?</a></li>
|
||
<li><a class="reference internal" href="#why-doesn-t-cpython-use-a-more-traditional-garbage-collection-scheme">为什么CPython不使用更传统的垃圾回收方案?</a></li>
|
||
<li><a class="reference internal" href="#why-isn-t-all-memory-freed-when-cpython-exits">CPython退出时为什么不释放所有内存?</a></li>
|
||
<li><a class="reference internal" href="#why-are-there-separate-tuple-and-list-data-types">为什么有单独的元组和列表数据类型?</a></li>
|
||
<li><a class="reference internal" href="#how-are-lists-implemented-in-cpython">列表是如何在CPython中实现的?</a></li>
|
||
<li><a class="reference internal" href="#how-are-dictionaries-implemented-in-cpython">字典是如何在CPython中实现的?</a></li>
|
||
<li><a class="reference internal" href="#why-must-dictionary-keys-be-immutable">为什么字典key必须是不可变的?</a></li>
|
||
<li><a class="reference internal" href="#why-doesn-t-list-sort-return-the-sorted-list">为什么 list.sort() 没有返回排序列表?</a></li>
|
||
<li><a class="reference internal" href="#how-do-you-specify-and-enforce-an-interface-spec-in-python">如何在Python中指定和实施接口规范?</a></li>
|
||
<li><a class="reference internal" href="#why-is-there-no-goto">为什么没有goto?</a></li>
|
||
<li><a class="reference internal" href="#why-can-t-raw-strings-r-strings-end-with-a-backslash">为什么原始字符串(r-strings)不能以反斜杠结尾?</a></li>
|
||
<li><a class="reference internal" href="#why-doesn-t-python-have-a-with-statement-for-attribute-assignments">为什么Python没有属性赋值的“with”语句?</a></li>
|
||
<li><a class="reference internal" href="#why-are-colons-required-for-the-if-while-def-class-statements">为什么 if/while/def/class语句需要冒号?</a></li>
|
||
<li><a class="reference internal" href="#why-does-python-allow-commas-at-the-end-of-lists-and-tuples">为什么Python在列表和元组的末尾允许使用逗号?</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>上一个主题</h4>
|
||
<p class="topless"><a href="programming.html"
|
||
title="上一章">编程常见问题</a></p>
|
||
<h4>下一个主题</h4>
|
||
<p class="topless"><a href="library.html"
|
||
title="下一章">代码库和插件 FAQ</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/faq/design.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/faq/design.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="library.html" title="代码库和插件 FAQ"
|
||
accesskey="N">下一页</a> |</li>
|
||
<li class="right" >
|
||
<a href="programming.html" title="编程常见问题"
|
||
accesskey="P">上一页</a> |</li>
|
||
|
||
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
|
||
<li><a href="https://www.python.org/">Python</a> »</li>
|
||
<li class="switchers">
|
||
<div class="language_switcher_placeholder"></div>
|
||
<div class="version_switcher_placeholder"></div>
|
||
</li>
|
||
<li>
|
||
|
||
</li>
|
||
<li id="cpython-language-and-version">
|
||
<a href="../index.html">3.8.20 Documentation</a> »
|
||
</li>
|
||
|
||
<li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python 常见问题</a> »</li>
|
||
<li class="right">
|
||
|
||
|
||
<div class="inline-search" role="search">
|
||
<form class="inline-search" action="../search.html" method="get">
|
||
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
|
||
<input type="submit" value="转向" />
|
||
<input type="hidden" name="check_keywords" value="yes" />
|
||
<input type="hidden" name="area" value="default" />
|
||
</form>
|
||
</div>
|
||
|
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section id="design-and-history-faq">
|
||
<h1><a class="toc-backref" href="#id3">设计和历史常见问题</a><a class="headerlink" href="#design-and-history-faq" title="永久链接至标题">¶</a></h1>
|
||
<div class="contents topic" id="id1">
|
||
<p class="topic-title">目录</p>
|
||
<ul class="simple">
|
||
<li><p><a class="reference internal" href="#design-and-history-faq" id="id3">设计和历史常见问题</a></p>
|
||
<ul>
|
||
<li><p><a class="reference internal" href="#why-does-python-use-indentation-for-grouping-of-statements" id="id4">为什么 Python 使用缩进来分组语句?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-am-i-getting-strange-results-with-simple-arithmetic-operations" id="id5">为什么简单的算术运算得到奇怪的结果?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-are-floating-point-calculations-so-inaccurate" id="id6">为什么浮点计算不准确?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-are-python-strings-immutable" id="id7">为什么Python字符串是不可变的?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-must-self-be-used-explicitly-in-method-definitions-and-calls" id="id8">为什么必须在方法定义和调用中显式使用“self”?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-can-t-i-use-an-assignment-in-an-expression" id="id9">为什么不能在表达式中赋值?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list" id="id10">为什么Python对某些功能(例如list.index())使用方法来实现,而其他功能(例如len(List))使用函数实现?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-is-join-a-string-method-instead-of-a-list-or-tuple-method" id="id11">为什么 join() 是一个字符串方法而不是列表或元组方法?</a></p></li>
|
||
<li><p><a class="reference internal" href="#how-fast-are-exceptions" id="id12">异常有多快?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-isn-t-there-a-switch-or-case-statement-in-python" id="id13">为什么Python中没有switch或case语句?</a></p></li>
|
||
<li><p><a class="reference internal" href="#can-t-you-emulate-threads-in-the-interpreter-instead-of-relying-on-an-os-specific-thread-implementation" id="id14">难道不能在解释器中模拟线程,而非得依赖特定于操作系统的线程实现吗?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-can-t-lambda-expressions-contain-statements" id="id15">为什么lambda表达式不能包含语句?</a></p></li>
|
||
<li><p><a class="reference internal" href="#can-python-be-compiled-to-machine-code-c-or-some-other-language" id="id16">可以将Python编译为机器代码,C或其他语言吗?</a></p></li>
|
||
<li><p><a class="reference internal" href="#how-does-python-manage-memory" id="id17">Python如何管理内存?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-doesn-t-cpython-use-a-more-traditional-garbage-collection-scheme" id="id18">为什么CPython不使用更传统的垃圾回收方案?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-isn-t-all-memory-freed-when-cpython-exits" id="id19">CPython退出时为什么不释放所有内存?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-are-there-separate-tuple-and-list-data-types" id="id20">为什么有单独的元组和列表数据类型?</a></p></li>
|
||
<li><p><a class="reference internal" href="#how-are-lists-implemented-in-cpython" id="id21">列表是如何在CPython中实现的?</a></p></li>
|
||
<li><p><a class="reference internal" href="#how-are-dictionaries-implemented-in-cpython" id="id22">字典是如何在CPython中实现的?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-must-dictionary-keys-be-immutable" id="id23">为什么字典key必须是不可变的?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-doesn-t-list-sort-return-the-sorted-list" id="id24">为什么 list.sort() 没有返回排序列表?</a></p></li>
|
||
<li><p><a class="reference internal" href="#how-do-you-specify-and-enforce-an-interface-spec-in-python" id="id25">如何在Python中指定和实施接口规范?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-is-there-no-goto" id="id26">为什么没有goto?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-can-t-raw-strings-r-strings-end-with-a-backslash" id="id27">为什么原始字符串(r-strings)不能以反斜杠结尾?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-doesn-t-python-have-a-with-statement-for-attribute-assignments" id="id28">为什么Python没有属性赋值的“with”语句?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-are-colons-required-for-the-if-while-def-class-statements" id="id29">为什么 if/while/def/class语句需要冒号?</a></p></li>
|
||
<li><p><a class="reference internal" href="#why-does-python-allow-commas-at-the-end-of-lists-and-tuples" id="id30">为什么Python在列表和元组的末尾允许使用逗号?</a></p></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<section id="why-does-python-use-indentation-for-grouping-of-statements">
|
||
<h2><a class="toc-backref" href="#id4">为什么 Python 使用缩进来分组语句?</a><a class="headerlink" href="#why-does-python-use-indentation-for-grouping-of-statements" title="永久链接至标题">¶</a></h2>
|
||
<p>Guido van Rossum 认为使用缩进进行分组非常优雅,并且大大提高了普通 Python 程序的清晰度。 大多数人在一段时间后就会喜欢上这个特性。</p>
|
||
<p>由于没有开始/结束括号,因此解析器感知的分组与人类读者之间不会存在分歧。 偶尔 C 程序员会遇到像这样的代码片段:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o"><=</span> <span class="n">y</span><span class="p">)</span>
|
||
<span class="n">x</span><span class="o">++</span><span class="p">;</span>
|
||
<span class="n">y</span><span class="o">--</span><span class="p">;</span>
|
||
<span class="n">z</span><span class="o">++</span><span class="p">;</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>如果条件为真,则只执行 <code class="docutils literal notranslate"><span class="pre">x++</span></code> 语句,但缩进会使你认为情况并非如此。即使是经验丰富的C程序员有时会长时间盯着它,想知道为什么即使 <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">></span> <span class="pre">y</span></code> , <code class="docutils literal notranslate"><span class="pre">y</span></code> 也在减少。</p>
|
||
<p>因为没有开始/结束括号,所以Python不太容易发生编码式冲突。在C中,括号可以放到许多不同的位置。如果您习惯于阅读和编写使用一种风格的代码,那么在阅读(或被要求编写)另一种风格时,您至少会感到有些不安。</p>
|
||
<p>许多编码风格将开始/结束括号单独放在一行上。这使得程序相当长,浪费了宝贵的屏幕空间,使得更难以对程序进行全面的了解。 理想情况下,函数应该适合一个屏幕(例如,20--30行)。 20 行 Python 可以完成比 20 行 C 更多的工作。 这不仅仅是由于没有开始/结束括号 -- 无需声明以及高层级的数据类型也是其中的原因 -- 但基于缩进的语法肯定有帮助。</p>
|
||
</section>
|
||
<section id="why-am-i-getting-strange-results-with-simple-arithmetic-operations">
|
||
<h2><a class="toc-backref" href="#id5">为什么简单的算术运算得到奇怪的结果?</a><a class="headerlink" href="#why-am-i-getting-strange-results-with-simple-arithmetic-operations" title="永久链接至标题">¶</a></h2>
|
||
<p>请看下一个问题。</p>
|
||
</section>
|
||
<section id="why-are-floating-point-calculations-so-inaccurate">
|
||
<h2><a class="toc-backref" href="#id6">为什么浮点计算不准确?</a><a class="headerlink" href="#why-are-floating-point-calculations-so-inaccurate" title="永久链接至标题">¶</a></h2>
|
||
<p>用户经常对这样的结果感到惊讶:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="mf">1.2</span> <span class="o">-</span> <span class="mf">1.0</span>
|
||
<span class="go">0.19999999999999996</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>并且认为这是 Python 中的一个 bug。其实不是这样。这与 Python 关系不大,而与底层平台如何处理浮点数字关系更大。</p>
|
||
<p>CPython 中的 <a class="reference internal" href="../library/functions.html#float" title="float"><code class="xref py py-class docutils literal notranslate"><span class="pre">float</span></code></a> 类型使用C语言的 <code class="docutils literal notranslate"><span class="pre">double</span></code> 类型进行存储。 <a class="reference internal" href="../library/functions.html#float" title="float"><code class="xref py py-class docutils literal notranslate"><span class="pre">float</span></code></a> 对象的值是以固定的精度(通常为 53 位)存储的二进制浮点数,由于 Python 使用 C 操作,而后者依赖于处理器中的硬件实现来执行浮点运算。 这意味着就浮点运算而言,Python 的行为类似于许多流行的语言,包括 C 和 Java。</p>
|
||
<p>许多可以轻松地用十进制表示的数字不能用二进制浮点表示。例如,在输入以下语句后:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">x</span> <span class="o">=</span> <span class="mf">1.2</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>为 <code class="docutils literal notranslate"><span class="pre">x</span></code> 存储的值是与十进制的值 <code class="docutils literal notranslate"><span class="pre">1.2</span></code> (非常接近) 的近似值,但不完全等于它。 在典型的机器上,实际存储的值是:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="mf">1.0011001100110011001100110011001100110011001100110011</span> <span class="p">(</span><span class="n">binary</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>它对应于十进制数值:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="mf">1.1999999999999999555910790149937383830547332763671875</span> <span class="p">(</span><span class="n">decimal</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>典型的 53 位精度为 Python 浮点数提供了 15-16 位小数的精度。</p>
|
||
<p>要获得更完整的解释,请参阅 Python 教程中的 <a class="reference internal" href="../tutorial/floatingpoint.html#tut-fp-issues"><span class="std std-ref">浮点算术</span></a> 一章。</p>
|
||
</section>
|
||
<section id="why-are-python-strings-immutable">
|
||
<h2><a class="toc-backref" href="#id7">为什么Python字符串是不可变的?</a><a class="headerlink" href="#why-are-python-strings-immutable" title="永久链接至标题">¶</a></h2>
|
||
<p>有几个优点。</p>
|
||
<p>一个是性能:知道字符串是不可变的,意味着我们可以在创建时为它分配空间,并且存储需求是固定不变的。这也是元组和列表之间区别的原因之一。</p>
|
||
<p>另一个优点是,Python 中的字符串被视为与数字一样“基本”。 任何动作都不会将值 8 更改为其他值,在 Python 中,任何动作都不会将字符串 "8" 更改为其他值。</p>
|
||
</section>
|
||
<section id="why-must-self-be-used-explicitly-in-method-definitions-and-calls">
|
||
<span id="why-self"></span><h2><a class="toc-backref" href="#id8">为什么必须在方法定义和调用中显式使用“self”?</a><a class="headerlink" href="#why-must-self-be-used-explicitly-in-method-definitions-and-calls" title="永久链接至标题">¶</a></h2>
|
||
<p>这个想法借鉴了 Modula-3 语言。 出于多种原因它被证明是非常有用的。</p>
|
||
<p>首先,更明显的显示出,使用的是方法或实例属性而不是局部变量。 阅读 <code class="docutils literal notranslate"><span class="pre">self.x</span></code> 或 <code class="docutils literal notranslate"><span class="pre">self.meth()</span></code> 可以清楚地表明,即使您不知道类的定义,也会使用实例变量或方法。在 C++ 中,可以通过缺少局部变量声明来判断(假设全局变量很少见或容易识别) —— 但是在 Python 中没有局部变量声明,所以必须查找类定义才能确定。 一些 C++ 和 Java 编码标准要求实例属性具有 <code class="docutils literal notranslate"><span class="pre">m_</span></code> 前缀,因此这种显式性在这些语言中仍然有用。</p>
|
||
<p>其次,这意味着如果要显式引用或从特定类调用该方法,不需要特殊语法。 在 C++ 中,如果你想使用在派生类中重写基类中的方法,你必须使用 <code class="docutils literal notranslate"><span class="pre">::</span></code> 运算符 -- 在 Python 中你可以编写 <code class="docutils literal notranslate"><span class="pre">baseclass.methodname(self,</span> <span class="pre"><argument</span> <span class="pre">list>)</span></code>。 这对于 <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> 方法非常有用,特别是在派生类方法想要扩展同名的基类方法,而必须以某种方式调用基类方法时。</p>
|
||
<p>最后,它解决了变量赋值的语法问题:为了 Python 中的局部变量(根据定义!)在函数体中赋值的那些变量(并且没有明确声明为全局)赋值,就必须以某种方式告诉解释器一个赋值是为了分配一个实例变量而不是一个局部变量,它最好是通过语法实现的(出于效率原因)。 C++ 通过声明来做到这一点,但是 Python 没有声明,仅仅为了这个目的而引入它们会很可惜。 使用显式的 <code class="docutils literal notranslate"><span class="pre">self.var</span></code> 很好地解决了这个问题。 类似地,对于使用实例变量,必须编写 <code class="docutils literal notranslate"><span class="pre">self.var</span></code> 意味着对方法内部的非限定名称的引用不必搜索实例的目录。 换句话说,局部变量和实例变量存在于两个不同的命名空间中,您需要告诉 Python 使用哪个命名空间。</p>
|
||
</section>
|
||
<section id="why-can-t-i-use-an-assignment-in-an-expression">
|
||
<span id="id2"></span><h2><a class="toc-backref" href="#id9">为什么不能在表达式中赋值?</a><a class="headerlink" href="#why-can-t-i-use-an-assignment-in-an-expression" title="永久链接至标题">¶</a></h2>
|
||
<p>自 Python 3.8 开始,你能做到的!</p>
|
||
<p>赋值表达式使用海象运算符 <cite>:=</cite> 在表达式中为变量赋值:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">while</span> <span class="n">chunk</span> <span class="o">:=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">200</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">chunk</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>请参阅 <span class="target" id="index-4"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0572"><strong>PEP 572</strong></a> 了解详情。</p>
|
||
</section>
|
||
<section id="why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list">
|
||
<h2><a class="toc-backref" href="#id10">为什么Python对某些功能(例如list.index())使用方法来实现,而其他功能(例如len(List))使用函数实现?</a><a class="headerlink" href="#why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list" title="永久链接至标题">¶</a></h2>
|
||
<p>正如Guido所说:</p>
|
||
<blockquote>
|
||
<div><p>(a) 对于某些操作,前缀表示法比后缀更容易阅读 -- 前缀(和中缀!)运算在数学中有着悠久的传统,就像在视觉上帮助数学家思考问题的记法。比较一下我们将 x*(a+b) 这样的公式改写为 x*a+x*b 的容易程度,以及使用原始OO符号做相同事情的笨拙程度。</p>
|
||
<p>(b) 当读到写有len(X)的代码时,就知道它要求的是某件东西的长度。这告诉我们两件事:结果是一个整数,参数是某种容器。相反,当阅读x.len()时,必须已经知道x是某种实现接口的容器,或者是从具有标准len()的类继承的容器。当没有实现映射的类有get()或key()方法,或者不是文件的类有write()方法时,我们偶尔会感到困惑。</p>
|
||
<p class="attribution">—<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2006-November/004643.html">https://mail.python.org/pipermail/python-3000/2006-November/004643.html</a></p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="why-is-join-a-string-method-instead-of-a-list-or-tuple-method">
|
||
<h2><a class="toc-backref" href="#id11">为什么 join() 是一个字符串方法而不是列表或元组方法?</a><a class="headerlink" href="#why-is-join-a-string-method-instead-of-a-list-or-tuple-method" title="永久链接至标题">¶</a></h2>
|
||
<p>从 Python 1.6 开始,字符串变得更像其他标准类型,当添加方法时,这些方法提供的功能与始终使用 String 模块的函数时提供的功能相同。这些新方法中的大多数已被广泛接受,但似乎让一些程序员感到不舒服的一种方法是:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="s2">", "</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s1">'1'</span><span class="p">,</span> <span class="s1">'2'</span><span class="p">,</span> <span class="s1">'4'</span><span class="p">,</span> <span class="s1">'8'</span><span class="p">,</span> <span class="s1">'16'</span><span class="p">])</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>结果如下:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="s2">"1, 2, 4, 8, 16"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>反对这种用法有两个常见的论点。</p>
|
||
<p>第一条是这样的:“使用字符串文本(String Constant)的方法看起来真的很难看”,答案是也许吧,但是字符串文本只是一个固定值。如果在绑定到字符串的名称上允许使用这些方法,则没有逻辑上的理由使其在文字上不可用。</p>
|
||
<p>第二个异议通常是这样的:“我实际上是在告诉序列使用字符串常量将其成员连接在一起”。遗憾的是并非如此。出于某种原因,把 <a class="reference internal" href="../library/stdtypes.html#str.split" title="str.split"><code class="xref py py-meth docutils literal notranslate"><span class="pre">split()</span></code></a> 作为一个字符串方法似乎要容易得多,因为在这种情况下,很容易看到:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="s2">"1, 2, 4, 8, 16"</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">", "</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>是对字符串文本的指令,用于返回由给定分隔符分隔的子字符串(或在默认情况下,返回任意空格)。</p>
|
||
<p><a class="reference internal" href="../library/stdtypes.html#str.join" title="str.join"><code class="xref py py-meth docutils literal notranslate"><span class="pre">join()</span></code></a> 是字符串方法,因为在使用该方法时,您告诉分隔符字符串去迭代一个字符串序列,并在相邻元素之间插入自身。此方法的参数可以是任何遵循序列规则的对象,包括您自己定义的任何新的类。对于字节和字节数组对象也有类似的方法。</p>
|
||
</section>
|
||
<section id="how-fast-are-exceptions">
|
||
<h2><a class="toc-backref" href="#id12">异常有多快?</a><a class="headerlink" href="#how-fast-are-exceptions" title="永久链接至标题">¶</a></h2>
|
||
<p>如果没有引发异常,则try/except块的效率极高。实际上捕获异常是昂贵的。在2.0之前的Python版本中,通常使用这个习惯用法:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
|
||
<span class="n">value</span> <span class="o">=</span> <span class="n">mydict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
|
||
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
|
||
<span class="n">mydict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">getvalue</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
|
||
<span class="n">value</span> <span class="o">=</span> <span class="n">mydict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>只有当你期望dict在任何时候都有key时,这才有意义。如果不是这样的话,你就是应该这样编码:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">mydict</span><span class="p">:</span>
|
||
<span class="n">value</span> <span class="o">=</span> <span class="n">mydict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">value</span> <span class="o">=</span> <span class="n">mydict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">getvalue</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>对于这种特定的情况,您还可以使用 <code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">dict.setdefault(key,</span> <span class="pre">getvalue(key))</span></code>,但前提是调用 <code class="docutils literal notranslate"><span class="pre">getvalue()</span></code> 足够便宜,因为在所有情况下都会对其进行评估。</p>
|
||
</section>
|
||
<section id="why-isn-t-there-a-switch-or-case-statement-in-python">
|
||
<h2><a class="toc-backref" href="#id13">为什么Python中没有switch或case语句?</a><a class="headerlink" href="#why-isn-t-there-a-switch-or-case-statement-in-python" title="永久链接至标题">¶</a></h2>
|
||
<p>你可以通过一系列 <code class="docutils literal notranslate"><span class="pre">if...</span> <span class="pre">elif...</span> <span class="pre">elif...</span> <span class="pre">else</span></code>.轻松完成这项工作。对于switch语句语法已经有了一些建议,但尚未就是否以及如何进行范围测试达成共识。有关完整的详细信息和当前状态,请参阅 <span class="target" id="index-5"></span><a class="pep reference external" href="https://www.python.org/dev/peps/pep-0275"><strong>PEP 275</strong></a> 。</p>
|
||
<p>对于需要从大量可能性中进行选择的情况,可以创建一个字典,将case 值映射到要调用的函数。例如:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">function_1</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
|
||
<span class="n">functions</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'a'</span><span class="p">:</span> <span class="n">function_1</span><span class="p">,</span>
|
||
<span class="s1">'b'</span><span class="p">:</span> <span class="n">function_2</span><span class="p">,</span>
|
||
<span class="s1">'c'</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">method_1</span><span class="p">,</span> <span class="o">...</span><span class="p">}</span>
|
||
|
||
<span class="n">func</span> <span class="o">=</span> <span class="n">functions</span><span class="p">[</span><span class="n">value</span><span class="p">]</span>
|
||
<span class="n">func</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>对于对象调用方法,可以通过使用 <a class="reference internal" href="../library/functions.html#getattr" title="getattr"><code class="xref py py-func docutils literal notranslate"><span class="pre">getattr()</span></code></a> 内置检索具有特定名称的方法来进一步简化:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">visit_a</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">...</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
<span class="o">...</span>
|
||
|
||
<span class="k">def</span> <span class="nf">dispatch</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
|
||
<span class="n">method_name</span> <span class="o">=</span> <span class="s1">'visit_'</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
|
||
<span class="n">method</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">method_name</span><span class="p">)</span>
|
||
<span class="n">method</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>建议对方法名使用前缀,例如本例中的 <code class="docutils literal notranslate"><span class="pre">visit_</span></code> 。如果没有这样的前缀,如果值来自不受信任的源,攻击者将能够调用对象上的任何方法。</p>
|
||
</section>
|
||
<section id="can-t-you-emulate-threads-in-the-interpreter-instead-of-relying-on-an-os-specific-thread-implementation">
|
||
<h2><a class="toc-backref" href="#id14">难道不能在解释器中模拟线程,而非得依赖特定于操作系统的线程实现吗?</a><a class="headerlink" href="#can-t-you-emulate-threads-in-the-interpreter-instead-of-relying-on-an-os-specific-thread-implementation" title="永久链接至标题">¶</a></h2>
|
||
<p>答案1: 不幸的是,解释器为每个Python堆栈帧推送至少一个C堆栈帧。此外,扩展可以随时回调Python。因此,一个完整的线程实现需要对C的线程支持。</p>
|
||
<p>答案2: 幸运的是, <a class="reference external" href="https://github.com/stackless-dev/stackless/wiki">Stackless Python</a> 有一个完全重新设计的解释器循环,可以避免C堆栈。</p>
|
||
</section>
|
||
<section id="why-can-t-lambda-expressions-contain-statements">
|
||
<h2><a class="toc-backref" href="#id15">为什么lambda表达式不能包含语句?</a><a class="headerlink" href="#why-can-t-lambda-expressions-contain-statements" title="永久链接至标题">¶</a></h2>
|
||
<p>Python 的 lambda 表达式不能包含语句,因为Python的语法框架不能处理嵌套在表达式内部的语句。然而,在 Python 中,这并不是一个严重的问题。 与其他语言中添加功能的 lambda 形式不同,Python 的 lambda 只是一种速记符号,如果您懒得定义函数的话。</p>
|
||
<p>函数已经是Python中的第一类对象,可以在本地范围内声明。 因此,使用lambda而不是本地定义的函数的唯一优点是你不需要为函数创建一个名称 -- 这只是一个分配了函数对象(与lambda表达式生成的对象类型完全相同)的局部变量!</p>
|
||
</section>
|
||
<section id="can-python-be-compiled-to-machine-code-c-or-some-other-language">
|
||
<h2><a class="toc-backref" href="#id16">可以将Python编译为机器代码,C或其他语言吗?</a><a class="headerlink" href="#can-python-be-compiled-to-machine-code-c-or-some-other-language" title="永久链接至标题">¶</a></h2>
|
||
<p><a class="reference external" href="http://cython.org/">Cython</a> 将带有可选注释的Python修改版本编译到C扩展中。 <a class="reference external" href="http://www.nuitka.net/">Nuitka</a> 是一个将Python编译成 C++ 代码的新兴编译器,旨在支持完整的Python语言。要编译成Java,可以考虑 <a class="reference external" href="https://voc.readthedocs.io">VOC</a> 。</p>
|
||
</section>
|
||
<section id="how-does-python-manage-memory">
|
||
<h2><a class="toc-backref" href="#id17">Python如何管理内存?</a><a class="headerlink" href="#how-does-python-manage-memory" title="永久链接至标题">¶</a></h2>
|
||
<p>Python 内存管理的细节取决于实现。 Python 的标准实现 <a class="reference internal" href="../glossary.html#term-cpython"><span class="xref std std-term">CPython</span></a> 使用引用计数来检测不可访问的对象,并使用另一种机制来收集引用循环,定期执行循环检测算法来查找不可访问的循环并删除所涉及的对象。 <a class="reference internal" href="../library/gc.html#module-gc" title="gc: Interface to the cycle-detecting garbage collector."><code class="xref py py-mod docutils literal notranslate"><span class="pre">gc</span></code></a> 模块提供了执行垃圾回收、获取调试统计信息和优化收集器参数的函数。</p>
|
||
<p>但是,其他实现(如 <a class="reference external" href="http://www.jython.org">Jython</a> 或 <a class="reference external" href="http://www.pypy.org">PyPy</a> ),)可以依赖不同的机制,如完全的垃圾回收器 。如果你的Python代码依赖于引用计数实现的行为,则这种差异可能会导致一些微妙的移植问题。</p>
|
||
<p>在一些Python实现中,以下代码(在CPython中工作的很好)可能会耗尽文件描述符:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">very_long_list_of_files</span><span class="p">:</span>
|
||
<span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">file</span><span class="p">)</span>
|
||
<span class="n">c</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>实际上,使用CPython的引用计数和析构函数方案, 每个新赋值的 <em>f</em> 都会关闭前一个文件。然而,对于传统的GC,这些文件对象只能以不同的时间间隔(可能很长的时间间隔)被收集(和关闭)。</p>
|
||
<p>如果要编写可用于任何python实现的代码,则应显式关闭该文件或使用 <a class="reference internal" href="../reference/compound_stmts.html#with"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">with</span></code></a> 语句;无论内存管理方案如何,这都有效:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">very_long_list_of_files</span><span class="p">:</span>
|
||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||
<span class="n">c</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="why-doesn-t-cpython-use-a-more-traditional-garbage-collection-scheme">
|
||
<h2><a class="toc-backref" href="#id18">为什么CPython不使用更传统的垃圾回收方案?</a><a class="headerlink" href="#why-doesn-t-cpython-use-a-more-traditional-garbage-collection-scheme" title="永久链接至标题">¶</a></h2>
|
||
<p>首先,这不是C标准特性,因此不能移植。(是的,我们知道Boehm GC库。它包含了 <em>大多数</em> 常见平台(但不是所有平台)的汇编代码,尽管它基本上是透明的,但也不是完全透明的; 要让Python使用它,需要使用补丁。)</p>
|
||
<p>当Python嵌入到其他应用程序中时,传统的GC也成为一个问题。在独立的Python中,可以用GC库提供的版本替换标准的malloc()和free(),嵌入Python的应用程序可能希望用 <em>它自己</em> 替代malloc()和free(),而可能不需要Python的。现在,CPython可以正确地实现malloc()和free()。</p>
|
||
</section>
|
||
<section id="why-isn-t-all-memory-freed-when-cpython-exits">
|
||
<h2><a class="toc-backref" href="#id19">CPython退出时为什么不释放所有内存?</a><a class="headerlink" href="#why-isn-t-all-memory-freed-when-cpython-exits" title="永久链接至标题">¶</a></h2>
|
||
<p>当Python退出时,从全局命名空间或Python模块引用的对象并不总是被释放。 如果存在循环引用,则可能发生这种情况 C库分配的某些内存也是不可能释放的(例如像Purify这样的工具会抱怨这些内容)。 但是,Python在退出时清理内存并尝试销毁每个对象。</p>
|
||
<p>如果要强制 Python 在释放时删除某些内容,请使用 <a class="reference internal" href="../library/atexit.html#module-atexit" title="atexit: Register and execute cleanup functions."><code class="xref py py-mod docutils literal notranslate"><span class="pre">atexit</span></code></a> 模块运行一个函数,强制删除这些内容。</p>
|
||
</section>
|
||
<section id="why-are-there-separate-tuple-and-list-data-types">
|
||
<h2><a class="toc-backref" href="#id20">为什么有单独的元组和列表数据类型?</a><a class="headerlink" href="#why-are-there-separate-tuple-and-list-data-types" title="永久链接至标题">¶</a></h2>
|
||
<p>虽然列表和元组在许多方面是相似的,但它们的使用方式通常是完全不同的。可以认为元组类似于Pascal记录或C结构;它们是相关数据的小集合,可以是不同类型的数据,可以作为一个组进行操作。例如,笛卡尔坐标适当地表示为两个或三个数字的元组。</p>
|
||
<p>另一方面,列表更像其他语言中的数组。它们倾向于持有不同数量的对象,所有对象都具有相同的类型,并且逐个操作。例如, <code class="docutils literal notranslate"><span class="pre">os.listdir('.')</span></code> 返回表示当前目录中的文件的字符串列表。如果向目录中添加了一两个文件,对此输出进行操作的函数通常不会中断。</p>
|
||
<p>元组是不可变的,这意味着一旦创建了元组,就不能用新值替换它的任何元素。列表是可变的,这意味着您始终可以更改列表的元素。只有不变元素可以用作字典的key,因此只能将元组和非列表用作key。</p>
|
||
</section>
|
||
<section id="how-are-lists-implemented-in-cpython">
|
||
<h2><a class="toc-backref" href="#id21">列表是如何在CPython中实现的?</a><a class="headerlink" href="#how-are-lists-implemented-in-cpython" title="永久链接至标题">¶</a></h2>
|
||
<p>CPython的列表实际上是可变长度的数组,而不是lisp风格的链表。该实现使用对其他对象的引用的连续数组,并在列表头结构中保留指向该数组和数组长度的指针。</p>
|
||
<p>这使得索引列表 <code class="docutils literal notranslate"><span class="pre">a[i]</span></code> 的操作成本与列表的大小或索引的值无关。</p>
|
||
<p>当添加或插入项时,将调整引用数组的大小。并采用了一些巧妙的方法来提高重复添加项的性能; 当数组必须增长时,会分配一些额外的空间,以便在接下来的几次中不需要实际调整大小。</p>
|
||
</section>
|
||
<section id="how-are-dictionaries-implemented-in-cpython">
|
||
<h2><a class="toc-backref" href="#id22">字典是如何在CPython中实现的?</a><a class="headerlink" href="#how-are-dictionaries-implemented-in-cpython" title="永久链接至标题">¶</a></h2>
|
||
<p>CPython的字典实现为可调整大小的哈希表。与B-树相比,这在大多数情况下为查找(目前最常见的操作)提供了更好的性能,并且实现更简单。</p>
|
||
<p>字典的工作方式是使用 <a class="reference internal" href="../library/functions.html#hash" title="hash"><code class="xref py py-func docutils literal notranslate"><span class="pre">hash()</span></code></a> 内置函数计算字典中存储的每个键的hash代码。hash代码根据键和每个进程的种子而变化很大;例如,"Python" 的hash值为-539294296,而"python"(一个按位不同的字符串)的hash值为1142331976。然后,hash代码用于计算内部数组中将存储该值的位置。假设您存储的键都具有不同的hash值,这意味着字典需要恒定的时间 -- O(1),用Big-O表示法 -- 来检索一个键。</p>
|
||
</section>
|
||
<section id="why-must-dictionary-keys-be-immutable">
|
||
<h2><a class="toc-backref" href="#id23">为什么字典key必须是不可变的?</a><a class="headerlink" href="#why-must-dictionary-keys-be-immutable" title="永久链接至标题">¶</a></h2>
|
||
<p>字典的哈希表实现使用从键值计算的哈希值来查找键。如果键是可变对象,则其值可能会发生变化,因此其哈希值也会发生变化。但是,由于无论谁更改键对象都无法判断它是否被用作字典键值,因此无法在字典中修改条目。然后,当你尝试在字典中查找相同的对象时,将无法找到它,因为其哈希值不同。如果你尝试查找旧值,也不会找到它,因为在该哈希表中找到的对象的值会有所不同。</p>
|
||
<p>如果你想要一个用列表索引的字典,只需先将列表转换为元组;用函数 <code class="docutils literal notranslate"><span class="pre">tuple(L)</span></code> 创建一个元组,其条目与列表 <code class="docutils literal notranslate"><span class="pre">L</span></code> 相同。 元组是不可变的,因此可以用作字典键。</p>
|
||
<p>已经提出的一些不可接受的解决方案:</p>
|
||
<ul>
|
||
<li><p>哈希按其地址(对象ID)列出。这不起作用,因为如果你构造一个具有相同值的新列表,它将无法找到;例如:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">mydict</span> <span class="o">=</span> <span class="p">{[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]:</span> <span class="s1">'12'</span><span class="p">}</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">mydict</span><span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]])</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>会引发一个 <a class="reference internal" href="../library/exceptions.html#KeyError" title="KeyError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">KeyError</span></code></a> 异常,因为第二行中使用的 <code class="docutils literal notranslate"><span class="pre">[1,</span> <span class="pre">2]</span></code> 的 id 与第一行中的 id 不同。换句话说,应该使用 <code class="docutils literal notranslate"><span class="pre">==</span></code> 来比较字典键,而不是使用 <a class="reference internal" href="../reference/expressions.html#is"><code class="xref std std-keyword docutils literal notranslate"><span class="pre">is</span></code></a> 。</p>
|
||
</li>
|
||
<li><p>使用列表作为键时进行复制。这没有用的,因为作为可变对象的列表可以包含对自身的引用,然后复制代码将进入无限循环。</p></li>
|
||
<li><p>允许列表作为键,但告诉用户不要修改它们。当你意外忘记或修改列表时,这将产生程序中的一类难以跟踪的错误。它还使一个重要的字典不变量无效: <code class="docutils literal notranslate"><span class="pre">d.keys()</span></code> 中的每个值都可用作字典的键。</p></li>
|
||
<li><p>将列表用作字典键后,应标记为其只读。问题是,它不仅仅是可以改变其值的顶级对象;你可以使用包含列表作为键的元组。将任何内容作为键关联到字典中都需要将从那里可到达的所有对象标记为只读 —— 并且自引用对象可能会导致无限循环。</p></li>
|
||
</ul>
|
||
<p>如果需要,可以使用以下方法来解决这个问题,但使用它需要你自担风险:你可以将一个可变结构包装在一个类实例中,该实例同时具有 <a class="reference internal" href="../reference/datamodel.html#object.__eq__" title="object.__eq__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__eq__()</span></code></a> 和 <a class="reference internal" href="../reference/datamodel.html#object.__hash__" title="object.__hash__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__hash__()</span></code></a> 方法。然后,你必须确保驻留在字典(或其他基于 hash 的结构)中的所有此类包装器对象的哈希值在对象位于字典(或其他结构)中时保持固定。:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ListWrapper</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">the_list</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">the_list</span> <span class="o">=</span> <span class="n">the_list</span>
|
||
|
||
<span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">the_list</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">the_list</span>
|
||
|
||
<span class="k">def</span> <span class="fm">__hash__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">l</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">the_list</span>
|
||
<span class="n">result</span> <span class="o">=</span> <span class="mi">98767</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">l</span><span class="p">)</span><span class="o">*</span><span class="mi">555</span>
|
||
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">el</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">l</span><span class="p">):</span>
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="n">result</span> <span class="o">=</span> <span class="n">result</span> <span class="o">+</span> <span class="p">(</span><span class="nb">hash</span><span class="p">(</span><span class="n">el</span><span class="p">)</span> <span class="o">%</span> <span class="mi">9999999</span><span class="p">)</span> <span class="o">*</span> <span class="mi">1001</span> <span class="o">+</span> <span class="n">i</span>
|
||
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
|
||
<span class="n">result</span> <span class="o">=</span> <span class="p">(</span><span class="n">result</span> <span class="o">%</span> <span class="mi">7777777</span><span class="p">)</span> <span class="o">+</span> <span class="n">i</span> <span class="o">*</span> <span class="mi">333</span>
|
||
<span class="k">return</span> <span class="n">result</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>注意,哈希计算由于列表的某些成员可能不可用以及算术溢出的可能性而变得复杂。</p>
|
||
<p>此外,必须始终如此,如果 <code class="docutils literal notranslate"><span class="pre">o1</span> <span class="pre">==</span> <span class="pre">o2</span></code> (即 <code class="docutils literal notranslate"><span class="pre">o1.__eq__(o2)</span> <span class="pre">is</span> <span class="pre">True</span></code> )则 <code class="docutils literal notranslate"><span class="pre">hash(o1)</span> <span class="pre">==</span> <span class="pre">hash(o2)</span></code> (即 <code class="docutils literal notranslate"><span class="pre">o1.__hash__()</span> <span class="pre">==</span> <span class="pre">o2.__hash__()</span></code> ),无论对象是否在字典中。 如果你不能满足这些限制,字典和其他基于 hash 的结构将会出错。</p>
|
||
<p>对于 ListWrapper ,只要包装器对象在字典中,包装列表就不能更改以避免异常。除非你准备好认真考虑需求以及不正确地满足这些需求的后果,否则不要这样做。请留意。</p>
|
||
</section>
|
||
<section id="why-doesn-t-list-sort-return-the-sorted-list">
|
||
<h2><a class="toc-backref" href="#id24">为什么 list.sort() 没有返回排序列表?</a><a class="headerlink" href="#why-doesn-t-list-sort-return-the-sorted-list" title="永久链接至标题">¶</a></h2>
|
||
<p>在性能很重要的情况下,仅仅为了排序而复制一份列表将是一种浪费。因此, <a class="reference internal" href="../library/stdtypes.html#list.sort" title="list.sort"><code class="xref py py-meth docutils literal notranslate"><span class="pre">list.sort()</span></code></a> 对列表进行了适当的排序。为了提醒您这一事实,它不会返回已排序的列表。这样,当您需要排序的副本,但也需要保留未排序的版本时,就不会意外地覆盖列表。</p>
|
||
<p>如果要返回新列表,请使用内置 <a class="reference internal" href="../library/functions.html#sorted" title="sorted"><code class="xref py py-func docutils literal notranslate"><span class="pre">sorted()</span></code></a> 函数。此函数从提供的可迭代列表中创建新列表,对其进行排序并返回。例如,下面是如何迭代遍历字典并按keys排序:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">mydict</span><span class="p">):</span>
|
||
<span class="o">...</span> <span class="c1"># do whatever with mydict[key]...</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="how-do-you-specify-and-enforce-an-interface-spec-in-python">
|
||
<h2><a class="toc-backref" href="#id25">如何在Python中指定和实施接口规范?</a><a class="headerlink" href="#how-do-you-specify-and-enforce-an-interface-spec-in-python" title="永久链接至标题">¶</a></h2>
|
||
<p>由C++和Java等语言提供的模块接口规范描述了模块的方法和函数的原型。许多人认为接口规范的编译时强制执行有助于构建大型程序。</p>
|
||
<p>Python 2.6添加了一个 <a class="reference internal" href="../library/abc.html#module-abc" title="abc: Abstract base classes according to :pep:`3119`."><code class="xref py py-mod docutils literal notranslate"><span class="pre">abc</span></code></a> 模块,允许定义抽象基类 (ABCs)。然后可以使用 <a class="reference internal" href="../library/functions.html#isinstance" title="isinstance"><code class="xref py py-func docutils literal notranslate"><span class="pre">isinstance()</span></code></a> 和 <a class="reference internal" href="../library/functions.html#issubclass" title="issubclass"><code class="xref py py-func docutils literal notranslate"><span class="pre">issubclass()</span></code></a> 来检查实例或类是否实现了特定的ABC。 <a class="reference internal" href="../library/collections.abc.html#module-collections.abc" title="collections.abc: Abstract base classes for containers"><code class="xref py py-mod docutils literal notranslate"><span class="pre">collections.abc</span></code></a> 模块定义了一组有用的ABCs 例如 <a class="reference internal" href="../library/collections.abc.html#collections.abc.Iterable" title="collections.abc.Iterable"><code class="xref py py-class docutils literal notranslate"><span class="pre">Iterable</span></code></a> , <a class="reference internal" href="../library/collections.abc.html#collections.abc.Container" title="collections.abc.Container"><code class="xref py py-class docutils literal notranslate"><span class="pre">Container</span></code></a> , 和 <a class="reference internal" href="../library/collections.abc.html#collections.abc.MutableMapping" title="collections.abc.MutableMapping"><code class="xref py py-class docutils literal notranslate"><span class="pre">MutableMapping</span></code></a></p>
|
||
<p>对于 Python,接口规范的许多好处可以通过组件的适当测试规程来获得。</p>
|
||
<p>一个好的模块测试套件既可以提供回归测试,也可以作为模块接口规范和一组示例。许多Python模块可以作为脚本运行,以提供简单的“自我测试”。即使是使用复杂外部接口的模块,也常常可以使用外部接口的简单“桩代码(stub)”模拟进行隔离测试。可以使用 <a class="reference internal" href="../library/doctest.html#module-doctest" title="doctest: Test pieces of code within docstrings."><code class="xref py py-mod docutils literal notranslate"><span class="pre">doctest</span></code></a> 和 <a class="reference internal" href="../library/unittest.html#module-unittest" title="unittest: Unit testing framework for Python."><code class="xref py py-mod docutils literal notranslate"><span class="pre">unittest</span></code></a> 模块或第三方测试框架来构造详尽的测试套件,以运行模块中的每一行代码。</p>
|
||
<p>适当的测试规程可以帮助在Python中构建大型的、复杂的应用程序以及接口规范。事实上,它可能会更好,因为接口规范不能测试程序的某些属性。例如, <code class="xref py py-meth docutils literal notranslate"><span class="pre">append()</span></code> 方法将向一些内部列表的末尾添加新元素;接口规范不能测试您的 <code class="xref py py-meth docutils literal notranslate"><span class="pre">append()</span></code> 实现是否能够正确执行此操作,但是在测试套件中检查这个属性是很简单的。</p>
|
||
<p>编写测试套件非常有用,您可能希望设计代码时着眼于使其易于测试。一种日益流行的技术是面向测试的开发,它要求在编写任何实际代码之前,首先编写测试套件的各个部分。当然,Python允许您草率行事,根本不编写测试用例。</p>
|
||
</section>
|
||
<section id="why-is-there-no-goto">
|
||
<h2><a class="toc-backref" href="#id26">为什么没有goto?</a><a class="headerlink" href="#why-is-there-no-goto" title="永久链接至标题">¶</a></h2>
|
||
<p>在 1970 年代人们了解到不受限制的 goto 可能导致混乱得像“意大利面”那样难以理解和修改的代码。 在高级语言中,它也是不必要的,只需有实现分支 (在 Python 中是使用 <code class="docutils literal notranslate"><span class="pre">if</span></code> 语句以及 <code class="docutils literal notranslate"><span class="pre">or</span></code>, <code class="docutils literal notranslate"><span class="pre">and</span></code> 和 <code class="docutils literal notranslate"><span class="pre">if-else</span></code> 表达式) 和循环 (使用 <code class="docutils literal notranslate"><span class="pre">while</span></code> 和 <code class="docutils literal notranslate"><span class="pre">for</span></code> 语句,并可能包含 <code class="docutils literal notranslate"><span class="pre">continue</span></code> 和 <code class="docutils literal notranslate"><span class="pre">break</span></code>) 的手段就足够了。</p>
|
||
<p>人们还可以使用异常捕获来提供甚至能跨函数调用的“结构化 goto”。 许多人认为异常可以方便地模拟 C, Fortran 和其他语言中所有合理使用的“go”或“goto”构造。 例如:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">label</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span> <span class="k">pass</span> <span class="c1"># declare a label</span>
|
||
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">condition</span><span class="p">:</span> <span class="k">raise</span> <span class="n">label</span><span class="p">()</span> <span class="c1"># goto label</span>
|
||
<span class="o">...</span>
|
||
<span class="k">except</span> <span class="n">label</span><span class="p">:</span> <span class="c1"># where to goto</span>
|
||
<span class="k">pass</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>但是不允许你跳到循环的中间,这通常被认为是滥用goto。谨慎使用。</p>
|
||
</section>
|
||
<section id="why-can-t-raw-strings-r-strings-end-with-a-backslash">
|
||
<h2><a class="toc-backref" href="#id27">为什么原始字符串(r-strings)不能以反斜杠结尾?</a><a class="headerlink" href="#why-can-t-raw-strings-r-strings-end-with-a-backslash" title="永久链接至标题">¶</a></h2>
|
||
<p>更准确地说,它们不能以奇数个反斜杠结束:结尾处的不成对反斜杠会转义结束引号字符,留下未结束的字符串。</p>
|
||
<p>原始字符串的设计是为了方便想要执行自己的反斜杠转义处理的处理器(主要是正则表达式引擎)创建输入。此类处理器将不匹配的尾随反斜杠视为错误,因此原始字符串不允许这样做。反过来,允许通过使用引号字符转义反斜杠转义字符串。当r-string用于它们的预期目的时,这些规则工作的很好。</p>
|
||
<p>如果您正在尝试构建Windows路径名,请注意所有Windows系统调用都使用正斜杠:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"/mydir/file.txt"</span><span class="p">)</span> <span class="c1"># works fine!</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>如果您正在尝试为DOS命令构建路径名,请尝试以下示例</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="nb">dir</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">"\this\is\my\dos\dir"</span> <span class="s2">"</span><span class="se">\\</span><span class="s2">"</span>
|
||
<span class="nb">dir</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">"\this\is\my\dos\dir\ "</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
|
||
<span class="nb">dir</span> <span class="o">=</span> <span class="s2">"</span><span class="se">\\</span><span class="s2">this</span><span class="se">\\</span><span class="s2">is</span><span class="se">\\</span><span class="s2">my</span><span class="se">\\</span><span class="s2">dos</span><span class="se">\\</span><span class="s2">dir</span><span class="se">\\</span><span class="s2">"</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="why-doesn-t-python-have-a-with-statement-for-attribute-assignments">
|
||
<h2><a class="toc-backref" href="#id28">为什么Python没有属性赋值的“with”语句?</a><a class="headerlink" href="#why-doesn-t-python-have-a-with-statement-for-attribute-assignments" title="永久链接至标题">¶</a></h2>
|
||
<p>Python有一个 'with' 语句,它封装了块的执行,在块的入口和出口调用代码。有些语言的结构是这样的:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">with</span> <span class="n">obj</span><span class="p">:</span>
|
||
<span class="n">a</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># equivalent to obj.a = 1</span>
|
||
<span class="n">total</span> <span class="o">=</span> <span class="n">total</span> <span class="o">+</span> <span class="mi">1</span> <span class="c1"># obj.total = obj.total + 1</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>在Python中,这样的结构是不明确的。</p>
|
||
<p>其他语言,如ObjectPascal、Delphi和C++ 使用静态类型,因此可以毫不含糊地知道分配给什么成员。这是静态类型的要点 -- 编译器 <em>总是</em> 在编译时知道每个变量的作用域。</p>
|
||
<p>Python使用动态类型。事先不可能知道在运行时引用哪个属性。可以动态地在对象中添加或删除成员属性。这使得无法通过简单的阅读就知道引用的是什么属性:局部属性、全局属性还是成员属性?</p>
|
||
<p>例如,采用以下不完整的代码段:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
|
||
<span class="k">with</span> <span class="n">a</span><span class="p">:</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>该代码段假设 "a" 必须有一个名为 "x" 的成员属性。然而,Python中并没有告诉解释器这一点。假设 "a" 是整数,会发生什么?如果有一个名为 "x" 的全局变量,它是否会在with块中使用?如您所见,Python的动态特性使得这样的选择更加困难。</p>
|
||
<p>然而,Python 可以通过赋值轻松实现 "with" 和类似语言特性(减少代码量)的主要好处。代替:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">function</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="o">.</span><span class="n">mydict</span><span class="p">[</span><span class="n">index</span><span class="p">][</span><span class="n">index</span><span class="p">]</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="mi">21</span>
|
||
<span class="n">function</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="o">.</span><span class="n">mydict</span><span class="p">[</span><span class="n">index</span><span class="p">][</span><span class="n">index</span><span class="p">]</span><span class="o">.</span><span class="n">b</span> <span class="o">=</span> <span class="mi">42</span>
|
||
<span class="n">function</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="o">.</span><span class="n">mydict</span><span class="p">[</span><span class="n">index</span><span class="p">][</span><span class="n">index</span><span class="p">]</span><span class="o">.</span><span class="n">c</span> <span class="o">=</span> <span class="mi">63</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>写成这样:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">ref</span> <span class="o">=</span> <span class="n">function</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="o">.</span><span class="n">mydict</span><span class="p">[</span><span class="n">index</span><span class="p">][</span><span class="n">index</span><span class="p">]</span>
|
||
<span class="n">ref</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="mi">21</span>
|
||
<span class="n">ref</span><span class="o">.</span><span class="n">b</span> <span class="o">=</span> <span class="mi">42</span>
|
||
<span class="n">ref</span><span class="o">.</span><span class="n">c</span> <span class="o">=</span> <span class="mi">63</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>这也具有提高执行速度的附带效果,因为 Python 在运行时解析名称绑定,而第二个版本只需要执行一次解析。</p>
|
||
</section>
|
||
<section id="why-are-colons-required-for-the-if-while-def-class-statements">
|
||
<h2><a class="toc-backref" href="#id29">为什么 if/while/def/class语句需要冒号?</a><a class="headerlink" href="#why-are-colons-required-for-the-if-while-def-class-statements" title="永久链接至标题">¶</a></h2>
|
||
<p>冒号主要用于增强可读性(ABC语言实验的结果之一)。考虑一下这个:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>与</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="p">:</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>注意第二种方法稍微容易一些。请进一步注意,在这个FAQ解答的示例中,冒号是如何设置的;这是英语中的标准用法。</p>
|
||
<p>另一个次要原因是冒号使带有语法突出显示的编辑器更容易工作;他们可以寻找冒号来决定何时需要增加缩进,而不必对程序文本进行更精细的解析。</p>
|
||
</section>
|
||
<section id="why-does-python-allow-commas-at-the-end-of-lists-and-tuples">
|
||
<h2><a class="toc-backref" href="#id30">为什么Python在列表和元组的末尾允许使用逗号?</a><a class="headerlink" href="#why-does-python-allow-commas-at-the-end-of-lists-and-tuples" title="永久链接至标题">¶</a></h2>
|
||
<p>Python 允许您在列表,元组和字典的末尾添加一个尾随逗号:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,]</span>
|
||
<span class="p">(</span><span class="s1">'a'</span><span class="p">,</span> <span class="s1">'b'</span><span class="p">,</span> <span class="s1">'c'</span><span class="p">,)</span>
|
||
<span class="n">d</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s2">"A"</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">5</span><span class="p">],</span>
|
||
<span class="s2">"B"</span><span class="p">:</span> <span class="p">[</span><span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">],</span> <span class="c1"># last trailing comma is optional but good style</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>有几个理由允许这样做。</p>
|
||
<p>如果列表,元组或字典的字面值分布在多行中,则更容易添加更多元素,因为不必记住在上一行中添加逗号。这些行也可以重新排序,而不会产生语法错误。</p>
|
||
<p>不小心省略逗号会导致难以诊断的错误。例如:</p>
|
||
<div class="highlight-python3 notranslate"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">=</span> <span class="p">[</span>
|
||
<span class="s2">"fee"</span><span class="p">,</span>
|
||
<span class="s2">"fie"</span>
|
||
<span class="s2">"foo"</span><span class="p">,</span>
|
||
<span class="s2">"fum"</span>
|
||
<span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>这个列表看起来有四个元素,但实际上包含三个 : "fee", "fiefoo" 和 "fum" 。总是加上逗号可以避免这个错误的来源。</p>
|
||
<p>允许尾随逗号也可以使编程代码更容易生成。</p>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<h3><a href="../contents.html">目录</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">设计和历史常见问题</a><ul>
|
||
<li><a class="reference internal" href="#why-does-python-use-indentation-for-grouping-of-statements">为什么 Python 使用缩进来分组语句?</a></li>
|
||
<li><a class="reference internal" href="#why-am-i-getting-strange-results-with-simple-arithmetic-operations">为什么简单的算术运算得到奇怪的结果?</a></li>
|
||
<li><a class="reference internal" href="#why-are-floating-point-calculations-so-inaccurate">为什么浮点计算不准确?</a></li>
|
||
<li><a class="reference internal" href="#why-are-python-strings-immutable">为什么Python字符串是不可变的?</a></li>
|
||
<li><a class="reference internal" href="#why-must-self-be-used-explicitly-in-method-definitions-and-calls">为什么必须在方法定义和调用中显式使用“self”?</a></li>
|
||
<li><a class="reference internal" href="#why-can-t-i-use-an-assignment-in-an-expression">为什么不能在表达式中赋值?</a></li>
|
||
<li><a class="reference internal" href="#why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list">为什么Python对某些功能(例如list.index())使用方法来实现,而其他功能(例如len(List))使用函数实现?</a></li>
|
||
<li><a class="reference internal" href="#why-is-join-a-string-method-instead-of-a-list-or-tuple-method">为什么 join() 是一个字符串方法而不是列表或元组方法?</a></li>
|
||
<li><a class="reference internal" href="#how-fast-are-exceptions">异常有多快?</a></li>
|
||
<li><a class="reference internal" href="#why-isn-t-there-a-switch-or-case-statement-in-python">为什么Python中没有switch或case语句?</a></li>
|
||
<li><a class="reference internal" href="#can-t-you-emulate-threads-in-the-interpreter-instead-of-relying-on-an-os-specific-thread-implementation">难道不能在解释器中模拟线程,而非得依赖特定于操作系统的线程实现吗?</a></li>
|
||
<li><a class="reference internal" href="#why-can-t-lambda-expressions-contain-statements">为什么lambda表达式不能包含语句?</a></li>
|
||
<li><a class="reference internal" href="#can-python-be-compiled-to-machine-code-c-or-some-other-language">可以将Python编译为机器代码,C或其他语言吗?</a></li>
|
||
<li><a class="reference internal" href="#how-does-python-manage-memory">Python如何管理内存?</a></li>
|
||
<li><a class="reference internal" href="#why-doesn-t-cpython-use-a-more-traditional-garbage-collection-scheme">为什么CPython不使用更传统的垃圾回收方案?</a></li>
|
||
<li><a class="reference internal" href="#why-isn-t-all-memory-freed-when-cpython-exits">CPython退出时为什么不释放所有内存?</a></li>
|
||
<li><a class="reference internal" href="#why-are-there-separate-tuple-and-list-data-types">为什么有单独的元组和列表数据类型?</a></li>
|
||
<li><a class="reference internal" href="#how-are-lists-implemented-in-cpython">列表是如何在CPython中实现的?</a></li>
|
||
<li><a class="reference internal" href="#how-are-dictionaries-implemented-in-cpython">字典是如何在CPython中实现的?</a></li>
|
||
<li><a class="reference internal" href="#why-must-dictionary-keys-be-immutable">为什么字典key必须是不可变的?</a></li>
|
||
<li><a class="reference internal" href="#why-doesn-t-list-sort-return-the-sorted-list">为什么 list.sort() 没有返回排序列表?</a></li>
|
||
<li><a class="reference internal" href="#how-do-you-specify-and-enforce-an-interface-spec-in-python">如何在Python中指定和实施接口规范?</a></li>
|
||
<li><a class="reference internal" href="#why-is-there-no-goto">为什么没有goto?</a></li>
|
||
<li><a class="reference internal" href="#why-can-t-raw-strings-r-strings-end-with-a-backslash">为什么原始字符串(r-strings)不能以反斜杠结尾?</a></li>
|
||
<li><a class="reference internal" href="#why-doesn-t-python-have-a-with-statement-for-attribute-assignments">为什么Python没有属性赋值的“with”语句?</a></li>
|
||
<li><a class="reference internal" href="#why-are-colons-required-for-the-if-while-def-class-statements">为什么 if/while/def/class语句需要冒号?</a></li>
|
||
<li><a class="reference internal" href="#why-does-python-allow-commas-at-the-end-of-lists-and-tuples">为什么Python在列表和元组的末尾允许使用逗号?</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>上一个主题</h4>
|
||
<p class="topless"><a href="programming.html"
|
||
title="上一章">编程常见问题</a></p>
|
||
<h4>下一个主题</h4>
|
||
<p class="topless"><a href="library.html"
|
||
title="下一章">代码库和插件 FAQ</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/faq/design.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="library.html" title="代码库和插件 FAQ"
|
||
>下一页</a> |</li>
|
||
<li class="right" >
|
||
<a href="programming.html" title="编程常见问题"
|
||
>上一页</a> |</li>
|
||
|
||
<li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
|
||
<li><a href="https://www.python.org/">Python</a> »</li>
|
||
<li class="switchers">
|
||
<div class="language_switcher_placeholder"></div>
|
||
<div class="version_switcher_placeholder"></div>
|
||
</li>
|
||
<li>
|
||
|
||
</li>
|
||
<li id="cpython-language-and-version">
|
||
<a href="../index.html">3.8.20 Documentation</a> »
|
||
</li>
|
||
|
||
<li class="nav-item nav-item-1"><a href="index.html" >Python 常见问题</a> »</li>
|
||
<li class="right">
|
||
|
||
|
||
<div class="inline-search" role="search">
|
||
<form class="inline-search" action="../search.html" method="get">
|
||
<input placeholder="快速搜索" aria-label="快速搜索" type="text" name="q" />
|
||
<input type="submit" value="转向" />
|
||
<input type="hidden" name="check_keywords" value="yes" />
|
||
<input type="hidden" name="area" value="default" />
|
||
</form>
|
||
</div>
|
||
|
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
<div class="footer">
|
||
© <a href="../copyright.html">版权所有</a> 2001-2024, Python Software Foundation.
|
||
<br />
|
||
This page is licensed under the Python Software Foundation License Version 2.
|
||
<br />
|
||
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
|
||
<br />
|
||
|
||
<br />
|
||
|
||
The Python Software Foundation is a non-profit corporation.
|
||
<a href="https://www.python.org/psf/donations/">Please donate.</a>
|
||
<br />
|
||
<br />
|
||
|
||
最后更新于 12月 09, 2024.
|
||
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
|
||
<br />
|
||
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 2.4.4.
|
||
</div>
|
||
|
||
</body>
|
||
</html> |