“Python/docs/3.9/howto/functional”的版本间差异

来自菜鸟教程
Python/docs/3.9/howto/functional
跳转至:导航、​搜索
(autoload)
 
(Page commit)
 
第1行: 第1行:
 +
{{DISPLAYTITLE:函数式编程 HOWTO — Python 文档}}
 
<div id="functional-programming-howto" class="section">
 
<div id="functional-programming-howto" class="section">
  
= Functional Programming HOWTO =
+
= 函数式编程HOWTO =
  
; Author
+
<dl>
: A. M. Kuchling
+
<dt>作者</dt>
; Release
+
<dd><ol>
: 0.32
+
<li><ol start="13">
 +
<li><p>库克林</p></li></ol>
 +
</li></ol>
 +
</dd>
 +
<dt>发布</dt>
 +
<dd><p>0.32</p></dd></dl>
  
In this document, we'll take a tour of Python's features suitable for
+
在本文档中,我们将了解适合以函数式风格实现程序的 Python 特性。 在介绍了函数式编程的概念之后,我们将看看语言特性,例如 [[../../glossary#term-iterator|iterator]]s [[../../glossary#term-generator|generator]]s 以及相关的库模块,例如 [[../../library/itertools#module-itertools|itertools]] [[../../library/functools#module-functools|functools]]
implementing programs in a functional style. After an introduction to the
 
concepts of functional programming, we'll look at language features such as
 
[[../../glossary#term-iterator|<span class="xref std std-term">iterator</span>]]s and [[../../glossary#term-generator|<span class="xref std std-term">generator</span>]]s and relevant library modules such as
 
[[../../library/itertools#module-itertools|<code>itertools</code>]] and [[../../library/functools#module-functools|<code>functools</code>]].
 
  
 
<div id="introduction" class="section">
 
<div id="introduction" class="section">
  
== Introduction ==
+
== 介绍 ==
  
This section explains the basic concept of functional programming; if
+
本节解释函数式编程的基本概念; 如果您只是对了解 Python 语言功能感兴趣,请跳到下一部分 [[#functional-howto-iterators|Iterators]]
you're just interested in learning about Python language features,
 
skip to the next section on [[#functional-howto-iterators|<span class="std std-ref">Iterators</span>]].
 
  
Programming languages support decomposing problems in several different ways:
+
编程语言支持以多种不同方式分解问题:
  
* Most programming languages are '''procedural''': programs are lists of instructions that tell the computer what to do with the program's input. C, Pascal, and even Unix shells are procedural languages.
+
* 大多数编程语言都是 '''过程化''' :程序是指令列表,告诉计算机如何处理程序的输入。 C、Pascal 甚至 Unix shell 都是过程语言。
* In '''declarative''' languages, you write a specification that describes the problem to be solved, and the language implementation figures out how to perform the computation efficiently. SQL is the declarative language you're most likely to be familiar with; a SQL query describes the data set you want to retrieve, and the SQL engine decides whether to scan tables or use indexes, which subclauses should be performed first, etc.
+
* '''声明性''' 语言中,您编写描述要解决的问题的规范,语言实现会弄清楚如何有效地执行计算。 SQL 是您最有可能熟悉的声明性语言; SQL 查询描述了您要检索的数据集,SQL 引擎决定是扫描表还是使用索引,应先执行哪些子条款等。
* '''Object-oriented''' programs manipulate collections of objects. Objects have internal state and support methods that query or modify this internal state in some way. Smalltalk and Java are object-oriented languages. C++ and Python are languages that support object-oriented programming, but don't force the use of object-oriented features.
+
* '''面向对象的'''程序操作对象的集合。 对象具有内部状态并支持以某种方式查询或修改此内部状态的方法。 Smalltalk Java 是面向对象的语言。 C++ Python 是支持面向对象编程的语言,但不强制使用面向对象的特性。
* '''Functional''' programming decomposes a problem into a set of functions. Ideally, functions only take inputs and produce outputs, and don't have any internal state that affects the output produced for a given input. Well-known functional languages include the ML family (Standard ML, OCaml, and other variants) and Haskell.
+
* '''函数式''' 编程将问题分解为一组函数。 理想情况下,函数只接受输入并产生输出,并且没有任何影响给定输入产生的输出的内部状态。 著名的函数式语言包括 ML 系列(标准 ML、OCaml 和其他变体)和 Haskell。
  
The designers of some computer languages choose to emphasize one
+
某些计算机语言的设计者选择强调一种特定的编程方法。 这通常会使编写使用不同方法的程序变得困难。 其他语言是支持多种不同方法的多范式语言。 Lisp、C++ Python 是多范式的; 您可以使用所有这些语言编写主要是过程性、面向对象或功能性的程序或库。 在一个大型程序中,可能会使用不同的方法编写不同的部分; 例如,GUI 可能是面向对象的,而处理逻辑是程序性的或功能性的。
particular approach to programming. This often makes it difficult to
 
write programs that use a different approach. Other languages are
 
multi-paradigm languages that support several different approaches.
 
Lisp, C++, and Python are multi-paradigm; you can write programs or
 
libraries that are largely procedural, object-oriented, or functional
 
in all of these languages. In a large program, different sections
 
might be written using different approaches; the GUI might be
 
object-oriented while the processing logic is procedural or
 
functional, for example.
 
  
In a functional program, input flows through a set of functions. Each function
+
在函数式程序中,输入流经一组函数。 每个函数对其输入进行操作并产生一些输出。 函数式风格不鼓励具有副作用的函数,这些函数会修改内部状态或进行在函数返回值中不可见的其他更改。 完全没有副作用的函数称为'''纯函数'''。 避免副作用意味着不使用随着程序运行而更新的数据结构; 每个函数的输出必须只依赖于它的输入。
operates on its input and produces some output. Functional style discourages
 
functions with side effects that modify internal state or make other changes
 
that aren't visible in the function's return value. Functions that have no side
 
effects at all are called '''purely functional'''. Avoiding side effects means
 
not using data structures that get updated as a program runs; every function's
 
output must only depend on its input.
 
  
Some languages are very strict about purity and don't even have assignment
+
有些语言对纯度非常严格,甚至没有赋值语句,例如 <code>a=3</code> <code>c = a + b</code>,但很难避免所有副作用,例如打印到屏幕或写入磁盘文件。 另一个例子是调用 [[../../library/functions#print|print()]] [[../../library/time#time|time.sleep()]] 函数,这两个函数都没有返回有用的值。 两者都只是因为它们向屏幕发送一些文本或暂停执行一秒钟的副作用而被调用。
statements such as <code>a=3</code> or <code>c = a + b</code>, but it's difficult to avoid all
 
side effects. Printing to the screen or writing to a disk file are side
 
effects, for example. For example, in Python a call to the [[../../library/functions#print|<code>print()</code>]] or
 
[[../../library/time#time|<code>time.sleep()</code>]] function both return no useful value; they're only called for
 
their side effects of sending some text to the screen or pausing execution for a
 
second.
 
  
Python programs written in functional style usually won't go to the extreme of
+
以函数式风格编写的 Python 程序通常不会走到避免所有 I/O 或所有分配的极端; 相反,他们将提供一个功能性的界面,但会在内部使用非功能性的特性。 例如,函数的实现仍然会使用对局部变量的赋值,但不会修改全局变量或产生其他副作用。
avoiding all I/O or all assignments; instead, they'll provide a
 
functional-appearing interface but will use non-functional features internally.
 
For example, the implementation of a function will still use assignments to
 
local variables, but won't modify global variables or have other side effects.
 
  
Functional programming can be considered the opposite of object-oriented
+
函数式编程可以被认为是面向对象编程的对立面。 对象是包含一些内部状态以及允许您修改此状态的一组方法调用的小胶囊,程序由进行正确的状态更改集组成。 函数式编程希望尽可能避免状态更改,并处理函数之间的数据流动。 在 Python 中,您可以通过编写接受和返回表示应用程序中的对象(电子邮件消息、事务等)的实例的函数来组合这两种方法。
programming. Objects are little capsules containing some internal state along
 
with a collection of method calls that let you modify this state, and programs
 
consist of making the right set of state changes. Functional programming wants
 
to avoid state changes as much as possible and works with data flowing between
 
functions. In Python you might combine the two approaches by writing functions
 
that take and return instances representing objects in your application (e-mail
 
messages, transactions, etc.).
 
  
Functional design may seem like an odd constraint to work under. Why should you
+
功能设计似乎是一个奇怪的工作限制。 为什么要避免对象和副作用? 函数式风格具有理论和实践优势:
avoid objects and side effects? There are theoretical and practical advantages
 
to the functional style:
 
  
* Formal provability.
+
* 正式的可证明性。
* Modularity.
+
* 模块化。
* Composability.
+
* 可组合性。
* Ease of debugging and testing.
+
* 易于调试和测试。
  
 
<div id="formal-provability" class="section">
 
<div id="formal-provability" class="section">
  
=== Formal provability ===
+
=== 形式证明 ===
  
A theoretical benefit is that it's easier to construct a mathematical proof that
+
理论上的好处是更容易构建函数式程序正确的数学证明。
a functional program is correct.
 
  
For a long time researchers have been interested in finding ways to
+
长期以来,研究人员一直对寻找数学证明程序正确的方法感兴趣。 这不同于在大量输入上测试程序并得出其输出通常是正确的结论,或阅读程序的源代码并得出代码看起来正确的结论; 相反,目标是严格证明程序为所有可能的输入产生正确的结果。
mathematically prove programs correct. This is different from testing a program
 
on numerous inputs and concluding that its output is usually correct, or reading
 
a program's source code and concluding that the code looks right; the goal is
 
instead a rigorous proof that a program produces the right result for all
 
possible inputs.
 
  
The technique used to prove programs correct is to write down '''invariants''',
+
用于证明程序正确的技术是写下 '''不变量''' 、输入数据和程序变量的属性,这些属性始终为真。 对于每一行代码,你然后证明如果不变量 X Y 为真 '''before''' 行被执行,略有不同的不变量 X' Y' 为真 '''after''' 行是执行。 这一直持续到程序结束,此时不变量应该与程序输出的所需条件相匹配。
properties of the input data and of the program's variables that are always
 
true. For each line of code, you then show that if invariants X and Y are true
 
'''before''' the line is executed, the slightly different invariants X' and Y' are
 
true '''after''' the line is executed. This continues until you reach the end of
 
the program, at which point the invariants should match the desired conditions
 
on the program's output.
 
  
Functional programming's avoidance of assignments arose because assignments are
+
函数式编程避免赋值的出现是因为这种技术很难处理赋值; 赋值可以破坏赋值之前为真的不变量,而不会产生任何可以向前传播的新不变量。
difficult to handle with this technique; assignments can break invariants that
 
were true before the assignment without producing any new invariants that can be
 
propagated onward.
 
  
Unfortunately, proving programs correct is largely impractical and not relevant
+
不幸的是,证明程序正确在很大程度上是不切实际的,并且与 Python 软件无关。 即使是微不足道的程序也需要几页长的证明; 中等复杂程序的正确性证明将是巨大的,并且您每天使用的程序(Python 解释器、您的 XML 解析器、您的 Web 浏览器)很少或没有一个可以被证明是正确的。 即使你写下或生成了一个证明,那么也会有验证这个证明的问题; 也许其中存在错误,并且您错误地认为您已经证明了该程序是正确的。
to Python software. Even trivial programs require proofs that are several pages
 
long; the proof of correctness for a moderately complicated program would be
 
enormous, and few or none of the programs you use daily (the Python interpreter,
 
your XML parser, your web browser) could be proven correct. Even if you wrote
 
down or generated a proof, there would then be the question of verifying the
 
proof; maybe there's an error in it, and you wrongly believe you've proved the
 
program correct.
 
  
  
第120行: 第64行:
 
<div id="modularity" class="section">
 
<div id="modularity" class="section">
  
=== Modularity ===
+
=== 模块化 ===
  
A more practical benefit of functional programming is that it forces you to
+
函数式编程的一个更实际的好处是它迫使您将问题分解成小块。 因此,程序更加模块化。 指定和编写一个只做一件事的小函数比一个执行复杂转换的大函数更容易。 小函数也更易于阅读和检查错误。
break apart your problem into small pieces. Programs are more modular as a
 
result. It's easier to specify and write a small function that does one thing
 
than a large function that performs a complicated transformation. Small
 
functions are also easier to read and to check for errors.
 
  
  
第132行: 第72行:
 
<div id="ease-of-debugging-and-testing" class="section">
 
<div id="ease-of-debugging-and-testing" class="section">
  
=== Ease of debugging and testing ===
+
=== 易于调试和测试 ===
  
Testing and debugging a functional-style program is easier.
+
测试和调试函数式程序更容易。
  
Debugging is simplified because functions are generally small and clearly
+
调试被简化,因为功能通常很小且明确指定。 当程序不工作时,每个函数都是一个接口点,您可以在其中检查数据是否正确。 您可以查看中间输入和输出以快速隔离导致错误的函数。
specified. When a program doesn't work, each function is an interface point
 
where you can check that the data are correct. You can look at the intermediate
 
inputs and outputs to quickly isolate the function that's responsible for a bug.
 
  
Testing is easier because each function is a potential subject for a unit test.
+
测试更容易,因为每个功能都是单元测试的潜在主题。 函数不依赖于在运行测试之前需要复制的系统状态; 相反,您只需合成正确的输入,然后检查输出是否符合预期。
Functions don't depend on system state that needs to be replicated before
 
running a test; instead you only have to synthesize the right input and then
 
check that the output matches expectations.
 
  
  
第150行: 第84行:
 
<div id="composability" class="section">
 
<div id="composability" class="section">
  
=== Composability ===
+
=== 可组合性 ===
  
As you work on a functional-style program, you'll write a number of functions
+
在处理函数式程序时,您将编写许多具有不同输入和输出的函数。 其中一些功能不可避免地专门用于特定应用程序,但其他功能将在各种程序中有用。 例如,采用目录路径并返回目录中所有 XML 文件的函数,或者采用文件名并返回其内容的函数,可以应用于许多不同的情况。
with varying inputs and outputs. Some of these functions will be unavoidably
 
specialized to a particular application, but others will be useful in a wide
 
variety of programs. For example, a function that takes a directory path and
 
returns all the XML files in the directory, or a function that takes a filename
 
and returns its contents, can be applied to many different situations.
 
  
Over time you'll form a personal library of utilities. Often you'll assemble
+
随着时间的推移,您将形成一个个人实用程序库。 通常,您会通过在新配置中安排现有函数并编写一些专门用于当前任务的函数来组装新程序。
new programs by arranging existing functions in a new configuration and writing
 
a few functions specialized for the current task.
 
  
  
第170行: 第97行:
  
 
<span id="functional-howto-iterators"></span>
 
<span id="functional-howto-iterators"></span>
== Iterators ==
+
== 迭代器 ==
  
I'll start by looking at a Python language feature that's an important
+
我将首先研究 Python 语言特性,它是编写函数式程序的重要基础:迭代器。
foundation for writing functional-style programs: iterators.
 
  
An iterator is an object representing a stream of data; this object returns the
+
迭代器是表示数据流的对象; 此对象一次返回一个元素的数据。 Python 迭代器必须支持名为 [[../../library/stdtypes#iterator|__next__()]] 的方法,该方法不接受任何参数并始终返回流的下一个元素。 如果流中没有更多元素,则 [[../../library/stdtypes#iterator|__next__()]] 必须引发 [[../../library/exceptions#StopIteration|StopIteration]] 异常。 不过,迭代器不一定是有限的; 编写一个产生无限数据流的迭代器是完全合理的。
data one element at a time. A Python iterator must support a method called
 
[[../../library/stdtypes#iterator|<code>__next__()</code>]] that takes no arguments and always returns the next
 
element of the stream. If there are no more elements in the stream,
 
[[../../library/stdtypes#iterator|<code>__next__()</code>]] must raise the [[../../library/exceptions#StopIteration|<code>StopIteration</code>]] exception.
 
Iterators don't have to be finite, though; it's perfectly reasonable to write
 
an iterator that produces an infinite stream of data.
 
  
The built-in [[../../library/functions#iter|<code>iter()</code>]] function takes an arbitrary object and tries to return
+
内置的 [[../../library/functions#iter|iter()]] 函数接受一个任意对象并尝试返回一个迭代器,该迭代器将返回该对象的内容或元素,如果该对象不支持迭代,则会引发 [[../../library/exceptions#TypeError|TypeError]]Python 的一些内置数据类型支持迭代,最常见的是列表和字典。 如果您可以获得一个迭代器,则该对象称为 [[../../glossary#term-iterable|iterable]]
an iterator that will return the object's contents or elements, raising
 
[[../../library/exceptions#TypeError|<code>TypeError</code>]] if the object doesn't support iteration. Several of Python's
 
built-in data types support iteration, the most common being lists and
 
dictionaries. An object is called [[../../glossary#term-iterable|<span class="xref std std-term">iterable</span>]] if you can get an iterator
 
for it.
 
  
You can experiment with the iteration interface manually:
+
您可以手动试验迭代界面:
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第196行: 第111行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; L = [1, 2, 3]
+
<syntaxhighlight lang="python">>>> L = [1, 2, 3]
&gt;&gt;&gt; it = iter(L)
+
>>> it = iter(L)
&gt;&gt;&gt; it   
+
>>> it   
&lt;...iterator object at ...&gt;
+
<...iterator object at ...>
&gt;&gt;&gt; it.__next__()  # same as next(it)
+
>>> it.__next__()  # same as next(it)
 
1
 
1
&gt;&gt;&gt; next(it)
+
>>> next(it)
 
2
 
2
&gt;&gt;&gt; next(it)
+
>>> next(it)
 
3
 
3
&gt;&gt;&gt; next(it)
+
>>> next(it)
 
Traceback (most recent call last):
 
Traceback (most recent call last):
   File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
+
   File "<stdin>", line 1, in <module>
 
StopIteration
 
StopIteration
&gt;&gt;&gt;</pre>
+
>>></syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Python expects iterable objects in several different contexts, the most
+
Python 期望在几个不同的上下文中可迭代对象,最重要的是 [[../../reference/compound_stmts#for|for]] 语句。 在语句 <code>for X in Y</code> 中,Y 必须是迭代器或 [[../../library/functions#iter|iter()]] 可以为其创建迭代器的某个对象。 这两个语句是等价的:
important being the [[../../reference/compound_stmts#for|<code>for</code>]] statement. In the statement <code>for X in Y</code>,
 
Y must be an iterator or some object for which [[../../library/functions#iter|<code>iter()</code>]] can create an
 
iterator. These two statements are equivalent:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第224行: 第136行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>for i in iter(obj):
+
<syntaxhighlight lang="python3">for i in iter(obj):
 
     print(i)
 
     print(i)
  
 
for i in obj:
 
for i in obj:
     print(i)</pre>
+
     print(i)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Iterators can be materialized as lists or tuples by using the [[../../library/stdtypes#list|<code>list()</code>]] or
+
通过使用 [[../../library/stdtypes#list|list()]] [[../../library/stdtypes#tuple|tuple()]] 构造函数,可以将迭代器具体化为列表或元组:
[[../../library/stdtypes#tuple|<code>tuple()</code>]] constructor functions:
 
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第240行: 第151行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; L = [1, 2, 3]
+
<syntaxhighlight lang="python">>>> L = [1, 2, 3]
&gt;&gt;&gt; iterator = iter(L)
+
>>> iterator = iter(L)
&gt;&gt;&gt; t = tuple(iterator)
+
>>> t = tuple(iterator)
&gt;&gt;&gt; t
+
>>> t
(1, 2, 3)</pre>
+
(1, 2, 3)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Sequence unpacking also supports iterators: if you know an iterator will return
+
序列解包也支持迭代器:如果你知道一个迭代器会返回 N 个元素,你可以将它们解包成一个 N 元组:
N elements, you can unpack them into an N-tuple:
 
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第256行: 第166行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; L = [1, 2, 3]
+
<syntaxhighlight lang="python">>>> L = [1, 2, 3]
&gt;&gt;&gt; iterator = iter(L)
+
>>> iterator = iter(L)
&gt;&gt;&gt; a, b, c = iterator
+
>>> a, b, c = iterator
&gt;&gt;&gt; a, b, c
+
>>> a, b, c
(1, 2, 3)</pre>
+
(1, 2, 3)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Built-in functions such as [[../../library/functions#max|<code>max()</code>]] and [[../../library/functions#min|<code>min()</code>]] can take a single
+
[[../../library/functions#max|max()]] [[../../library/functions#min|min()]] 等内置函数可以采用单个迭代器参数,并返回最大或最小元素。 <code>&quot;in&quot;</code> <code>&quot;not in&quot;</code> 运算符也支持迭代器:如果在迭代器返回的流中找到 X,则 <code>X in iterator</code> 为真。 如果迭代器是无限的,你会遇到明显的问题; [[../../library/functions#max|max()]], [[../../library/functions#min|min()]] 永远不会返回,如果元素 X 永远不会出现在流中,则 <code>&quot;in&quot;</code> <code>&quot;not in&quot;</code> 算子赢了也不回。
iterator argument and will return the largest or smallest element. The <code>&quot;in&quot;</code>
 
and <code>&quot;not in&quot;</code> operators also support iterators: <code>X in iterator</code> is true if
 
X is found in the stream returned by the iterator. You'll run into obvious
 
problems if the iterator is infinite; [[../../library/functions#max|<code>max()</code>]], [[../../library/functions#min|<code>min()</code>]]
 
will never return, and if the element X never appears in the stream, the
 
<code>&quot;in&quot;</code> and <code>&quot;not in&quot;</code> operators won't return either.
 
  
Note that you can only go forward in an iterator; there's no way to get the
+
请注意,您只能在迭代器中前进; 无法获取前一个元素、重置迭代器或复制它。 迭代器对象可以选择提供这些附加功能,但迭代器协议仅指定 [[../../library/stdtypes#iterator|__next__()]] 方法。 因此,函数可能会消耗迭代器的所有输出,如果您需要对同一流执行不同的操作,则必须创建一个新的迭代器。
previous element, reset the iterator, or make a copy of it. Iterator objects
 
can optionally provide these additional capabilities, but the iterator protocol
 
only specifies the [[../../library/stdtypes#iterator|<code>__next__()</code>]] method. Functions may therefore
 
consume all of the iterator's output, and if you need to do something different
 
with the same stream, you'll have to create a new iterator.
 
  
 
<div id="data-types-that-support-iterators" class="section">
 
<div id="data-types-that-support-iterators" class="section">
  
=== Data Types That Support Iterators ===
+
=== 支持迭代器的数据类型 ===
  
We've already seen how lists and tuples support iterators. In fact, any Python
+
我们已经看到列表和元组如何支持迭代器。 事实上,任何 Python 序列类型,例如字符串,都会自动支持创建迭代器。
sequence type, such as strings, will automatically support creation of an
 
iterator.
 
  
Calling [[../../library/functions#iter|<code>iter()</code>]] on a dictionary returns an iterator that will loop over the
+
在字典上调用 [[../../library/functions#iter|iter()]] 会返回一个迭代器,该迭代器将遍历字典的键:
dictionary's keys:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第295行: 第191行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
+
<syntaxhighlight lang="python3">>>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
 
...      'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
 
...      'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
&gt;&gt;&gt; for key in m:
+
>>> for key in m:
 
...    print(key, m[key])
 
...    print(key, m[key])
 
Jan 1
 
Jan 1
第310行: 第206行:
 
Oct 10
 
Oct 10
 
Nov 11
 
Nov 11
Dec 12</pre>
+
Dec 12</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Note that starting with Python 3.7, dictionary iteration order is guaranteed
+
请注意,从 Python 3.7 开始,字典迭代顺序保证与插入顺序相同。 在早期版本中,行为未指定并且可能因实现而异。
to be the same as the insertion order. In earlier versions, the behaviour was
 
unspecified and could vary between implementations.
 
  
Applying [[../../library/functions#iter|<code>iter()</code>]] to a dictionary always loops over the keys, but
+
[[../../library/functions#iter|iter()]] 应用于字典总是遍历键,但字典具有返回其他迭代器的方法。 如果要迭代值或键/值对,可以显式调用 [[../../library/stdtypes#dict|values()]] [[../../library/stdtypes#dict|items()]] 方法来获得合适的迭代器。
dictionaries have methods that return other iterators. If you want to iterate
 
over values or key/value pairs, you can explicitly call the
 
[[../../library/stdtypes#dict|<code>values()</code>]] or [[../../library/stdtypes#dict|<code>items()</code>]] methods to get an appropriate
 
iterator.
 
  
The [[../../library/stdtypes#dict|<code>dict()</code>]] constructor can accept an iterator that returns a finite stream
+
[[../../library/stdtypes#dict|dict()]] 构造函数可以接受一个迭代器,它返回一个有限的 <code>(key, value)</code> 元组流:
of <code>(key, value)</code> tuples:
 
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第332行: 第221行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; L = [('Italy', 'Rome'), ('France', 'Paris'), ('US', 'Washington DC')]
+
<syntaxhighlight lang="python">>>> L = [('Italy', 'Rome'), ('France', 'Paris'), ('US', 'Washington DC')]
&gt;&gt;&gt; dict(iter(L))
+
>>> dict(iter(L))
{'Italy': 'Rome', 'France': 'Paris', 'US': 'Washington DC'}</pre>
+
{'Italy': 'Rome', 'France': 'Paris', 'US': 'Washington DC'}</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Files also support iteration by calling the [[../../library/io#io.TextIOBase|<code>readline()</code>]]
+
文件还通过调用 [[../../library/io#io.TextIOBase|readline()]] 方法来支持迭代,直到文件中没有更多行。 这意味着您可以像这样读取文件的每一行:
method until there are no more lines in the file. This means you can read each
 
line of a file like this:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第347行: 第234行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>for line in file:
+
<syntaxhighlight lang="python3">for line in file:
 
     # do something for each line
 
     # do something for each line
     ...</pre>
+
     ...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Sets can take their contents from an iterable and let you iterate over the set's
+
集合可以从可迭代对象中获取它们的内容,并让您迭代集合的元素:
elements:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第361行: 第247行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>S = {2, 3, 5, 7, 11, 13}
+
<syntaxhighlight lang="python3">S = {2, 3, 5, 7, 11, 13}
 
for i in S:
 
for i in S:
     print(i)</pre>
+
     print(i)</syntaxhighlight>
  
 
</div>
 
</div>
第374行: 第260行:
 
<div id="generator-expressions-and-list-comprehensions" class="section">
 
<div id="generator-expressions-and-list-comprehensions" class="section">
  
== Generator expressions and list comprehensions ==
+
== 生成器表达式和列表推导式 ==
  
Two common operations on an iterator's output are 1) performing some operation
+
迭代器输出的两个常见操作是 1) 对每个元素执行一些操作,2) 选择满足某些条件的元素子集。 例如,给定一个字符串列表,您可能希望从每一行中去除尾随空格或提取包含给定子字符串的所有字符串。
for every element, 2) selecting a subset of elements that meet some condition.
 
For example, given a list of strings, you might want to strip off trailing
 
whitespace from each line or extract all the strings containing a given
 
substring.
 
  
List comprehensions and generator expressions (short form: &quot;listcomps&quot; and
+
列表推导式和生成器表达式(简称:“listcomps”和“genexps”)是此类操作的简明符号,借用自函数式编程语言 Haskell (https://www.haskell.org/) . 您可以使用以下代码从字符串流中去除所有空格:
&quot;genexps&quot;) are a concise notation for such operations, borrowed from the
 
functional programming language Haskell (https://www.haskell.org/). You can strip
 
all the whitespace from a stream of strings with the following code:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第391行: 第270行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>line_list = ['  line 1\n', 'line 2  \n', ...]
+
<syntaxhighlight lang="python3">line_list = ['  line 1\n', 'line 2  \n', ...]
  
 
# Generator expression -- returns iterator
 
# Generator expression -- returns iterator
第397行: 第276行:
  
 
# List comprehension -- returns list
 
# List comprehension -- returns list
stripped_list = [line.strip() for line in line_list]</pre>
+
stripped_list = [line.strip() for line in line_list]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
You can select only certain elements by adding an <code>&quot;if&quot;</code> condition:
+
您可以通过添加 <code>&quot;if&quot;</code> 条件来仅选择某些元素:
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第408行: 第287行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>stripped_list = [line.strip() for line in line_list
+
<syntaxhighlight lang="python3">stripped_list = [line.strip() for line in line_list
                 if line != &quot;&quot;]</pre>
+
                 if line != ""]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
With a list comprehension, you get back a Python list; <code>stripped_list</code> is a
+
通过列表理解,你会得到一个 Python 列表; <code>stripped_list</code> 是包含结果行的列表,而不是迭代器。 生成器表达式返回一个迭代器,它根据需要计算值,不需要一次实现所有值。 这意味着如果您正在使用返回无限流或大量数据的迭代器,则列表推导式没有用。 在这些情况下,生成器表达式更可取。
list containing the resulting lines, not an iterator. Generator expressions
 
return an iterator that computes the values as necessary, not needing to
 
materialize all the values at once. This means that list comprehensions aren't
 
useful if you're working with iterators that return an infinite stream or a very
 
large amount of data. Generator expressions are preferable in these situations.
 
  
Generator expressions are surrounded by parentheses (&quot;()&quot;) and list
+
生成器表达式用括号(“()”)括起来,列表推导式用方括号(“[]”)括起来。 生成器表达式具有以下形式:
comprehensions are surrounded by square brackets (&quot;[]&quot;). Generator expressions
 
have the form:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第429行: 第301行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>( expression for expr in sequence1
+
<syntaxhighlight lang="python3">( expression for expr in sequence1
 
             if condition1
 
             if condition1
 
             for expr2 in sequence2
 
             for expr2 in sequence2
第436行: 第308行:
 
             if condition3
 
             if condition3
 
             for exprN in sequenceN
 
             for exprN in sequenceN
             if conditionN )</pre>
+
             if conditionN )</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Again, for a list comprehension only the outside brackets are different (square
+
同样,对于列表理解,只有外括号不同(方括号而不是圆括号)。
brackets instead of parentheses).
 
  
The elements of the generated output will be the successive values of
+
生成的输出的元素将是 <code>expression</code> 的连续值。 <code>if</code> 子句都是可选的; 如果存在,仅当 <code>condition</code> 为真时才会评估 <code>expression</code> 并将其添加到结果中。
<code>expression</code>. The <code>if</code> clauses are all optional; if present, <code>expression</code>
 
is only evaluated and added to the result when <code>condition</code> is true.
 
  
Generator expressions always have to be written inside parentheses, but the
+
生成器表达式总是必须写在括号内,但发出函数调用信号的括号也算在内。 如果您想创建一个将立即传递给函数的迭代器,您可以编写:
parentheses signalling a function call also count. If you want to create an
 
iterator that will be immediately passed to a function you can write:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第456行: 第323行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>obj_total = sum(obj.count for obj in list_all_objects())</pre>
+
<syntaxhighlight lang="python3">obj_total = sum(obj.count for obj in list_all_objects())</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The <code>for...in</code> clauses contain the sequences to be iterated over. The
+
<code>for...in</code> 子句包含要迭代的序列。 序列的长度不必相同,因为它们是从左到右迭代的, '''不是''' 并行。 对于 <code>sequence1</code> 中的每个元素,<code>sequence2</code> 从头开始循环。 <code>sequence3</code> 然后为来自 <code>sequence1</code> <code>sequence2</code> 的每个结果元素对循环。
sequences do not have to be the same length, because they are iterated over from
 
left to right, '''not''' in parallel. For each element in <code>sequence1</code>,
 
<code>sequence2</code> is looped over from the beginning. <code>sequence3</code> is then looped
 
over for each resulting pair of elements from <code>sequence1</code> and <code>sequence2</code>.
 
  
To put it another way, a list comprehension or generator expression is
+
换句话说,列表推导式或生成器表达式等效于以下 Python 代码:
equivalent to the following Python code:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第474行: 第336行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>for expr1 in sequence1:
+
<syntaxhighlight lang="python3">for expr1 in sequence1:
 
     if not (condition1):
 
     if not (condition1):
 
         continue  # Skip this element
 
         continue  # Skip this element
第486行: 第348行:
  
 
             # Output the value of
 
             # Output the value of
             # the expression.</pre>
+
             # the expression.</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This means that when there are multiple <code>for...in</code> clauses but no <code>if</code>
+
这意味着当有多个 <code>for...in</code> 子句但没有 <code>if</code> 子句时,结果输出的长度将等于所有序列长度的乘积。 如果您有两个长度为 3 的列表,则输出列表的长度为 9 个元素:
clauses, the length of the resulting output will be equal to the product of the
 
lengths of all the sequences. If you have two lists of length 3, the output
 
list is 9 elements long:
 
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第500行: 第359行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; seq1 = 'abc'
+
<syntaxhighlight lang="python">>>> seq1 = 'abc'
&gt;&gt;&gt; seq2 = (1, 2, 3)
+
>>> seq2 = (1, 2, 3)
&gt;&gt;&gt; [(x, y) for x in seq1 for y in seq2]   
+
>>> [(x, y) for x in seq1 for y in seq2]   
 
[('a', 1), ('a', 2), ('a', 3),
 
[('a', 1), ('a', 2), ('a', 3),
 
  ('b', 1), ('b', 2), ('b', 3),
 
  ('b', 1), ('b', 2), ('b', 3),
  ('c', 1), ('c', 2), ('c', 3)]</pre>
+
  ('c', 1), ('c', 2), ('c', 3)]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
To avoid introducing an ambiguity into Python's grammar, if <code>expression</code> is
+
为了避免在 Python 的语法中引入歧义,如果 <code>expression</code> 正在创建一个元组,它必须用括号括起来。 下面的第一个列表理解是一个语法错误,而第二个是正确的:
creating a tuple, it must be surrounded with parentheses. The first list
 
comprehension below is a syntax error, while the second one is correct:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第518行: 第375行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre># Syntax error
+
<syntaxhighlight lang="python3"># Syntax error
 
[x, y for x in seq1 for y in seq2]
 
[x, y for x in seq1 for y in seq2]
 
# Correct
 
# Correct
[(x, y) for x in seq1 for y in seq2]</pre>
+
[(x, y) for x in seq1 for y in seq2]</syntaxhighlight>
  
 
</div>
 
</div>
第530行: 第387行:
 
<div id="generators" class="section">
 
<div id="generators" class="section">
  
== Generators ==
+
== 发电机 ==
  
Generators are a special class of functions that simplify the task of writing
+
生成器是一类特殊的函数,可以简化编写迭代器的任务。 常规函数计算一个值并返回它,但生成器返回一个迭代器,它返回一个值流。
iterators. Regular functions compute a value and return it, but generators
 
return an iterator that returns a stream of values.
 
  
You're doubtless familiar with how regular function calls work in Python or C.
+
您无疑熟悉 Python C 中常规函数调用的工作方式。 当您调用一个函数时,它会获得一个私有命名空间,在该命名空间中创建了它的局部变量。 当函数到达<code>return</code>语句时,局部变量被销毁,并将值返回给调用者。 稍后对同一函数的调用会创建一个新的私有命名空间和一组新的局部变量。 但是,如果在退出函数时没有丢弃局部变量呢? 如果您稍后可以恢复它停止的功能怎么办? 这就是生成器提供的; 它们可以被认为是可恢复的功能。
When you call a function, it gets a private namespace where its local variables
 
are created. When the function reaches a <code>return</code> statement, the local
 
variables are destroyed and the value is returned to the caller. A later call
 
to the same function creates a new private namespace and a fresh set of local
 
variables. But, what if the local variables weren't thrown away on exiting a
 
function? What if you could later resume the function where it left off? This
 
is what generators provide; they can be thought of as resumable functions.
 
  
Here's the simplest example of a generator function:
+
这是生成器函数的最简单示例:
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第551行: 第399行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; def generate_ints(N):
+
<syntaxhighlight lang="python">>>> def generate_ints(N):
 
...    for i in range(N):
 
...    for i in range(N):
...        yield i</pre>
+
...        yield i</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Any function containing a [[../../reference/simple_stmts#yield|<code>yield</code>]] keyword is a generator function;
+
任何包含 [[../../reference/simple_stmts#yield|yield]] 关键字的函数都是生成器函数; 这是由 Python [[../../glossary#term-bytecode|bytecode]] 编译器检测到的,该编译器因此专门编译该函数。
this is detected by Python's [[../../glossary#term-bytecode|<span class="xref std std-term">bytecode</span>]] compiler which compiles the
 
function specially as a result.
 
  
When you call a generator function, it doesn't return a single value; instead it
+
当您调用生成器函数时,它不会返回单个值; 相反,它返回一个支持迭代器协议的生成器对象。 在执行 <code>yield</code> 表达式时,生成器输出 <code>i</code> 的值,类似于 <code>return</code> 语句。 <code>yield</code> <code>return</code> 语句之间的最大区别在于,在到达 <code>yield</code> 时,生成器的执行状态被挂起并保留局部变量。 在下次调用生成器的 [[../../reference/expressions#generator|__next__()]] 方法时,该函数将继续执行。
returns a generator object that supports the iterator protocol. On executing
 
the <code>yield</code> expression, the generator outputs the value of <code>i</code>, similar to a
 
<code>return</code> statement. The big difference between <code>yield</code> and a <code>return</code>
 
statement is that on reaching a <code>yield</code> the generator's state of execution is
 
suspended and local variables are preserved. On the next call to the
 
generator's [[../../reference/expressions#generator|<code>__next__()</code>]] method, the function will resume
 
executing.
 
  
Here's a sample usage of the <code>generate_ints()</code> generator:
+
以下是 <code>generate_ints()</code> 生成器的示例用法:
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第577行: 第416行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; gen = generate_ints(3)
+
<syntaxhighlight lang="python">>>> gen = generate_ints(3)
&gt;&gt;&gt; gen   
+
>>> gen   
&lt;generator object generate_ints at ...&gt;
+
<generator object generate_ints at ...>
&gt;&gt;&gt; next(gen)
+
>>> next(gen)
 
0
 
0
&gt;&gt;&gt; next(gen)
+
>>> next(gen)
 
1
 
1
&gt;&gt;&gt; next(gen)
+
>>> next(gen)
 
2
 
2
&gt;&gt;&gt; next(gen)
+
>>> next(gen)
 
Traceback (most recent call last):
 
Traceback (most recent call last):
   File &quot;stdin&quot;, line 1, in &lt;module&gt;
+
   File "stdin", line 1, in <module>
   File &quot;stdin&quot;, line 2, in generate_ints
+
   File "stdin", line 2, in generate_ints
StopIteration</pre>
+
StopIteration</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
You could equally write <code>for i in generate_ints(5)</code>, or <code>a, b, c = generate_ints(3)</code>.
+
你同样可以写 <code>for i in generate_ints(5)</code> <code>a, b, c = generate_ints(3)</code>
  
Inside a generator function, <code>return value</code> causes <code>StopIteration(value)</code>
+
在一个生成器函数中,<code>return value</code> 导致 <code>StopIteration(value)</code> [[../../reference/expressions#generator|__next__()]] 方法被引发。 一旦发生这种情况,或者到达函数的底部,值的处理结束并且生成器不能产生任何进一步的值。
to be raised from the [[../../reference/expressions#generator|<code>__next__()</code>]] method. Once this happens, or
 
the bottom of the function is reached, the procession of values ends and the
 
generator cannot yield any further values.
 
  
You could achieve the effect of generators manually by writing your own class
+
您可以通过编写自己的类并将生成器的所有局部变量存储为实例变量来手动实现生成器的效果。 例如,可以通过将 <code>self.count</code> 设置为 0 并让 [[../../library/stdtypes#iterator|__next__()]] 方法递增 <code>self.count</code> 并返回它来返回整数列表。 然而,对于一个中等复杂的生成器,编写相应的类可能会更加混乱。
and storing all the local variables of the generator as instance variables. For
 
example, returning a list of integers could be done by setting <code>self.count</code> to
 
0, and having the [[../../library/stdtypes#iterator|<code>__next__()</code>]] method increment <code>self.count</code> and
 
return it.
 
However, for a moderately complicated generator, writing a corresponding class
 
can be much messier.
 
  
The test suite included with Python's library,
+
Python 库中包含的测试套件 [[#id1|:source:`Lib/test/test_generators.py`]] 包含许多更有趣的示例。 这是一个使用生成器递归实现树的有序遍历的生成器。
[https://github.com/python/cpython/tree/3.9/Lib/test/test_generators.py Lib/test/test_generators.py], contains
 
a number of more interesting examples. Here's one generator that implements an
 
in-order traversal of a tree using generators recursively.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第619行: 第446行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre># A recursive generator that generates Tree leaves in in-order.
+
<syntaxhighlight lang="python3"># A recursive generator that generates Tree leaves in in-order.
 
def inorder(t):
 
def inorder(t):
 
     if t:
 
     if t:
第628行: 第455行:
  
 
         for x in inorder(t.right):
 
         for x in inorder(t.right):
             yield x</pre>
+
             yield x</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Two other examples in <code>test_generators.py</code> produce solutions for the N-Queens
+
<code>test_generators.py</code> 中的另外两个示例为 N-Queens 问题(将 N 个皇后放在 NxN 棋盘上,以便没有皇后威胁另一个皇后)和骑士之旅(找到一条将骑士带到每个方格的路线)的解决方案一个 NxN 棋盘,无需两次访问任何方块)。
problem (placing N queens on an NxN chess board so that no queen threatens
 
another) and the Knight's Tour (finding a route that takes a knight to every
 
square of an NxN chessboard without visiting any square twice).
 
  
 
<div id="passing-values-into-a-generator" class="section">
 
<div id="passing-values-into-a-generator" class="section">
  
=== Passing values into a generator ===
+
=== 将值传递给生成器 ===
  
In Python 2.4 and earlier, generators only produced output. Once a generator's
+
Python 2.4 及更早版本中,生成器只产生输出。 一旦调用生成器的代码来创建迭代器,在恢复执行时就无法将任何新信息传递给函数。 您可以通过让生成器查看全局变量或通过传入一些调用者然后修改的可变对象来组合这种能力,但这些方法是混乱的。
code was invoked to create an iterator, there was no way to pass any new
 
information into the function when its execution is resumed. You could hack
 
together this ability by making the generator look at a global variable or by
 
passing in some mutable object that callers then modify, but these approaches
 
are messy.
 
  
In Python 2.5 there's a simple way to pass values into a generator.
+
Python 2.5 中,有一种简单的方法可以将值传递给生成器。 [[../../reference/simple_stmts#yield|yield]] 变成了一个表达式,返回一个可以赋值给变量或以其他方式操作的值:
[[../../reference/simple_stmts#yield|<code>yield</code>]] became an expression, returning a value that can be assigned to
 
a variable or otherwise operated on:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第657行: 第474行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>val = (yield i)</pre>
+
<syntaxhighlight lang="python3">val = (yield i)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
I recommend that you '''always''' put parentheses around a <code>yield</code> expression
+
我建议您 '''始终''' 在使用返回值执行某些操作时在 <code>yield</code> 表达式周围放置括号,如上例所示。 括号并不总是必要的,但总是添加它们更容易,而不必记住何时需要它们。
when you're doing something with the returned value, as in the above example.
 
The parentheses aren't always necessary, but it's easier to always add them
 
instead of having to remember when they're needed.
 
  
(<span id="index-0" class="target"></span>[https://www.python.org/dev/peps/pep-0342 '''PEP 342'''] explains the exact rules, which are that a <code>yield</code>-expression must
+
<span id="index-0" class="target"></span>[https://www.python.org/dev/peps/pep-0342 PEP 342] 解释了确切的规则,即 <code>yield</code> 表达式必须始终用括号括起来,除非它出现在右侧的顶级表达式中-作业的手边。 这意味着您可以编写 <code>val = yield i</code>,但在进行操作时必须使用括号,如 <code>val = (yield i) + 12</code>。)
always be parenthesized except when it occurs at the top-level expression on the
 
right-hand side of an assignment. This means you can write <code>val = yield i</code>
 
but have to use parentheses when there's an operation, as in <code>val = (yield i) + 12</code>.)
 
  
Values are sent into a generator by calling its [[../../reference/expressions#generator|<code>send(value)</code>]] method. This method resumes the generator's code and the
+
通过调用其 [[../../reference/expressions#generator|send(value)]] 方法将值发送到生成器。 此方法恢复生成器的代码并且 <code>yield</code> 表达式返回指定的值。 如果调用常规的 [[../../reference/expressions#generator|__next__()]] 方法,则 <code>yield</code> 返回 <code>None</code>
<code>yield</code> expression returns the specified value. If the regular
 
[[../../reference/expressions#generator|<code>__next__()</code>]] method is called, the <code>yield</code> returns <code>None</code>.
 
  
Here's a simple counter that increments by 1 and allows changing the value of
+
这是一个简单的计数器,递增 1 并允许更改内部计数器的值。
the internal counter.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第683行: 第491行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def counter(maximum):
+
<syntaxhighlight lang="python3">def counter(maximum):
 
     i = 0
 
     i = 0
     while i &lt; maximum:
+
     while i < maximum:
 
         val = (yield i)
 
         val = (yield i)
 
         # If value provided, change counter
 
         # If value provided, change counter
第691行: 第499行:
 
             i = val
 
             i = val
 
         else:
 
         else:
             i += 1</pre>
+
             i += 1</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
And here's an example of changing the counter:
+
这是更改计数器的示例:
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第702行: 第510行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; it = counter(10)   
+
<syntaxhighlight lang="python">>>> it = counter(10)   
&gt;&gt;&gt; next(it)   
+
>>> next(it)   
 
0
 
0
&gt;&gt;&gt; next(it)   
+
>>> next(it)   
 
1
 
1
&gt;&gt;&gt; it.send(8)   
+
>>> it.send(8)   
 
8
 
8
&gt;&gt;&gt; next(it)   
+
>>> next(it)   
 
9
 
9
&gt;&gt;&gt; next(it)   
+
>>> next(it)   
 
Traceback (most recent call last):
 
Traceback (most recent call last):
   File &quot;t.py&quot;, line 15, in &lt;module&gt;
+
   File "t.py", line 15, in <module>
 
     it.next()
 
     it.next()
StopIteration</pre>
+
StopIteration</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Because <code>yield</code> will often be returning <code>None</code>, you should always check for
+
因为 <code>yield</code> 经常会返回 <code>None</code>,所以你应该经常检查这种情况。 不要只在表达式中使用它的值,除非您确定 [[../../reference/expressions#generator|send()]] 方法将是用于恢复生成器函数的唯一方法。
this case. Don't just use its value in expressions unless you're sure that the
 
[[../../reference/expressions#generator|<code>send()</code>]] method will be the only method used to resume your
 
generator function.
 
  
In addition to [[../../reference/expressions#generator|<code>send()</code>]], there are two other methods on
+
除了 [[../../reference/expressions#generator|send()]] 之外,生成器还有另外两种方法:
generators:
 
  
 
<ul>
 
<ul>
<li><p>[[../../reference/expressions#generator|<code>throw(type, value=None, traceback=None)</code>]] is used to
+
<li><p>[[../../reference/expressions#generator|throw(type, value=None, traceback=None)]] 用于在生成器内部引发异常; 异常由 <code>yield</code> 表达式引发,其中生成器的执行暂停。</p></li>
raise an exception inside the generator; the exception is raised by the
+
<li><p>[[../../reference/expressions#generator|close()]] 在生成器内部引发 [[../../library/exceptions#GeneratorExit|GeneratorExit]] 异常以终止迭代。 收到此异常时,生成器的代码必须引发 [[../../library/exceptions#GeneratorExit|GeneratorExit]] [[../../library/exceptions#StopIteration|StopIteration]]; 捕获异常并执行其他任何操作都是非法的,并且会触发 [[../../library/exceptions#RuntimeError|RuntimeError]][[../../reference/expressions#generator|close()]] 在生成器被垃圾回收时也会被 Python 的垃圾回收器调用。</p>
<code>yield</code> expression where the generator's execution is paused.</p></li>
+
<p>如果您需要在发生 [[../../library/exceptions#GeneratorExit|GeneratorExit]] 时运行清理代码,我建议使用 <code>try: ... finally:</code> 套件而不是捕获 [[../../library/exceptions#GeneratorExit|GeneratorExit]]</p></li></ul>
<li><p>[[../../reference/expressions#generator|<code>close()</code>]] raises a [[../../library/exceptions#GeneratorExit|<code>GeneratorExit</code>]] exception inside the
 
generator to terminate the iteration. On receiving this exception, the
 
generator's code must either raise [[../../library/exceptions#GeneratorExit|<code>GeneratorExit</code>]] or
 
[[../../library/exceptions#StopIteration|<code>StopIteration</code>]]; catching the exception and doing anything else is
 
illegal and will trigger a [[../../library/exceptions#RuntimeError|<code>RuntimeError</code>]]. [[../../reference/expressions#generator|<code>close()</code>]]
 
will also be called by Python's garbage collector when the generator is
 
garbage-collected.</p>
 
<p>If you need to run cleanup code when a [[../../library/exceptions#GeneratorExit|<code>GeneratorExit</code>]] occurs, I suggest
 
using a <code>try: ... finally:</code> suite instead of catching [[../../library/exceptions#GeneratorExit|<code>GeneratorExit</code>]].</p></li></ul>
 
  
The cumulative effect of these changes is to turn generators from one-way
+
这些变化的累积效应是将生成者从信息的单向生产者转变为生产者和消费者。
producers of information into both producers and consumers.
 
  
Generators also become '''coroutines''', a more generalized form of subroutines.
+
生成器也变成了 '''协程''' ,一种更通用的子程序形式。 子程序在一个点进入并在另一个点退出(函数的顶部,和一个 <code>return</code> 语句),但是协程可以在许多不同的点进入、退出和恢复(<code>yield</code> ] 语句)。
Subroutines are entered at one point and exited at another point (the top of the
 
function, and a <code>return</code> statement), but coroutines can be entered, exited,
 
and resumed at many different points (the <code>yield</code> statements).
 
  
  
第756行: 第547行:
 
<div id="built-in-functions" class="section">
 
<div id="built-in-functions" class="section">
  
== Built-in functions ==
+
== 内置功能 ==
  
Let's look in more detail at built-in functions often used with iterators.
+
让我们更详细地了解经常与迭代器一起使用的内置函数。
  
Two of Python's built-in functions, [[../../library/functions#map|<code>map()</code>]] and [[../../library/functions#filter|<code>filter()</code>]] duplicate the
+
Python 的两个内置函数 [[../../library/functions#map|map()]] [[../../library/functions#filter|filter()]] 复制了生成器表达式的特征:
features of generator expressions:
 
  
 
<dl>
 
<dl>
<dt>[[../../library/functions#map|<code>map(f, iterA, iterB, ...)</code>]] returns an iterator over the sequence</dt>
+
<dt>[[../../library/functions#map|map(f, iterA, iterB, ...)]] 返回序列上的迭代器</dt>
<dd><p><code>f(iterA[0], iterB[0]), f(iterA[1], iterB[1]), f(iterA[2], iterB[2]), ...</code>.</p>
+
<dd><p><code>f(iterA[0], iterB[0]), f(iterA[1], iterB[1]), f(iterA[2], iterB[2]), ...</code></p>
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
  
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; def upper(s):
+
<syntaxhighlight lang="python">>>> def upper(s):
...    return s.upper()</pre>
+
...    return s.upper()</syntaxhighlight>
  
 
</div>
 
</div>
第780行: 第570行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; list(map(upper, ['sentence', 'fragment']))
+
<syntaxhighlight lang="python">>>> list(map(upper, ['sentence', 'fragment']))
 
['SENTENCE', 'FRAGMENT']
 
['SENTENCE', 'FRAGMENT']
&gt;&gt;&gt; [upper(s) for s in ['sentence', 'fragment']]
+
>>> [upper(s) for s in ['sentence', 'fragment']]
['SENTENCE', 'FRAGMENT']</pre>
+
['SENTENCE', 'FRAGMENT']</syntaxhighlight>
  
 
</div>
 
</div>
第789行: 第579行:
 
</div></dd></dl>
 
</div></dd></dl>
  
You can of course achieve the same effect with a list comprehension.
+
您当然可以使用列表理解来达到相同的效果。
  
[[../../library/functions#filter|<code>filter(predicate, iter)</code>]] returns an iterator over all the
+
[[../../library/functions#filter|filter(predicate, iter)]] 返回一个遍历所有满足特定条件的序列元素的迭代器,同样被列表推导式复制。 '''predicate''' 是一个返回某个条件真值的函数; 要与 [[../../library/functions#filter|filter()]] 一起使用,谓词必须采用单个值。
sequence elements that meet a certain condition, and is similarly duplicated by
 
list comprehensions. A '''predicate''' is a function that returns the truth
 
value of some condition; for use with [[../../library/functions#filter|<code>filter()</code>]], the predicate must take a
 
single value.
 
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第801行: 第587行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; def is_even(x):
+
<syntaxhighlight lang="python">>>> def is_even(x):
...    return (x % 2) == 0</pre>
+
...    return (x % 2) == 0</syntaxhighlight>
  
 
</div>
 
</div>
第811行: 第597行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; list(filter(is_even, range(10)))
+
<syntaxhighlight lang="python">>>> list(filter(is_even, range(10)))
[0, 2, 4, 6, 8]</pre>
+
[0, 2, 4, 6, 8]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This can also be written as a list comprehension:
+
这也可以写成列表理解:
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第823行: 第609行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; list(x for x in range(10) if is_even(x))
+
<syntaxhighlight lang="python">>>> list(x for x in range(10) if is_even(x))
[0, 2, 4, 6, 8]</pre>
+
[0, 2, 4, 6, 8]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/functions#enumerate|<code>enumerate(iter, start=0)</code>]] counts off the elements in the
+
[[../../library/functions#enumerate|enumerate(iter, start=0)]] 对迭代中的元素进行计数,返回包含计数(来自 ''start'')和每个元素的 2 元组。
iterable returning 2-tuples containing the count (from ''start'') and
 
each element.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第837行: 第621行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; for item in enumerate(['subject', 'verb', 'object']):
+
<syntaxhighlight lang="python3">>>> for item in enumerate(['subject', 'verb', 'object']):
 
...    print(item)
 
...    print(item)
 
(0, 'subject')
 
(0, 'subject')
 
(1, 'verb')
 
(1, 'verb')
(2, 'object')</pre>
+
(2, 'object')</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/functions#enumerate|<code>enumerate()</code>]] is often used when looping through a list and recording the
+
[[../../library/functions#enumerate|enumerate()]] 在循环遍历列表并记录满足特定条件的索引时经常使用:
indexes at which certain conditions are met:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第853行: 第636行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>f = open('data.txt', 'r')
+
<syntaxhighlight lang="python3">f = open('data.txt', 'r')
 
for i, line in enumerate(f):
 
for i, line in enumerate(f):
 
     if line.strip() == '':
 
     if line.strip() == '':
         print('Blank line at line #%i' % i)</pre>
+
         print('Blank line at line #%i' % i)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/functions#sorted|<code>sorted(iterable, key=None, reverse=False)</code>]] collects all the
+
[[../../library/functions#sorted|sorted(iterable, key=None, reverse=False)]] 将iterable的所有元素收集到一个列表中,对列表进行排序,返回排序后的结果。 ''key'' ''reverse'' 参数被传递到构造列表的 [[../../library/stdtypes#list|sort()]] 方法。
elements of the iterable into a list, sorts the list, and returns the sorted
 
result. The ''key'' and ''reverse'' arguments are passed through to the
 
constructed list's [[../../library/stdtypes#list|<code>sort()</code>]] method.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第870行: 第650行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; import random
+
<syntaxhighlight lang="python3">>>> import random
&gt;&gt;&gt; # Generate 8 random numbers between [0, 10000)
+
>>> # Generate 8 random numbers between [0, 10000)
&gt;&gt;&gt; rand_list = random.sample(range(10000), 8)
+
>>> rand_list = random.sample(range(10000), 8)
&gt;&gt;&gt; rand_list   
+
>>> rand_list   
 
[769, 7953, 9828, 6431, 8442, 9878, 6213, 2207]
 
[769, 7953, 9828, 6431, 8442, 9878, 6213, 2207]
&gt;&gt;&gt; sorted(rand_list)   
+
>>> sorted(rand_list)   
 
[769, 2207, 6213, 6431, 7953, 8442, 9828, 9878]
 
[769, 2207, 6213, 6431, 7953, 8442, 9828, 9878]
&gt;&gt;&gt; sorted(rand_list, reverse=True)   
+
>>> sorted(rand_list, reverse=True)   
[9878, 9828, 8442, 7953, 6431, 6213, 2207, 769]</pre>
+
[9878, 9828, 8442, 7953, 6431, 6213, 2207, 769]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
(For a more detailed discussion of sorting, see the [[../sorting#sortinghowto|<span class="std std-ref">Sorting HOW TO</span>]].)
+
(有关排序的更详细讨论,请参阅 [[../sorting#sortinghowto|Sorting HOW TO]]。)
  
The [[../../library/functions#any|<code>any(iter)</code>]] and [[../../library/functions#all|<code>all(iter)</code>]] built-ins look at the
+
[[../../library/functions#any|any(iter)]] [[../../library/functions#all|all(iter)]] 内置函数查看可迭代内容的真值。 [[../../library/functions#any|any()]] 如果迭代中的任何元素为真值,则返回 <code>True</code>,如果所有元素都为真值,则 [[../../library/functions#all|all()]] 返回 <code>True</code>真实值:
truth values of an iterable's contents. [[../../library/functions#any|<code>any()</code>]] returns <code>True</code> if any element
 
in the iterable is a true value, and [[../../library/functions#all|<code>all()</code>]] returns <code>True</code> if all of the
 
elements are true values:
 
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第894行: 第671行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; any([0, 1, 0])
+
<syntaxhighlight lang="python">>>> any([0, 1, 0])
 
True
 
True
&gt;&gt;&gt; any([0, 0, 0])
+
>>> any([0, 0, 0])
 
False
 
False
&gt;&gt;&gt; any([1, 1, 1])
+
>>> any([1, 1, 1])
 
True
 
True
&gt;&gt;&gt; all([0, 1, 0])
+
>>> all([0, 1, 0])
 
False
 
False
&gt;&gt;&gt; all([0, 0, 0])
+
>>> all([0, 0, 0])
 
False
 
False
&gt;&gt;&gt; all([1, 1, 1])
+
>>> all([1, 1, 1])
True</pre>
+
True</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/functions#zip|<code>zip(iterA, iterB, ...)</code>]] takes one element from each iterable and
+
[[../../library/functions#zip|zip(iterA, iterB, ...)]] 从每个可迭代对象中取出一个元素并在元组中返回它们:
returns them in a tuple:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第917行: 第693行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>zip(['a', 'b', 'c'], (1, 2, 3)) =&gt;
+
<syntaxhighlight lang="python3">zip(['a', 'b', 'c'], (1, 2, 3)) =>
   ('a', 1), ('b', 2), ('c', 3)</pre>
+
   ('a', 1), ('b', 2), ('c', 3)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
It doesn't construct an in-memory list and exhaust all the input iterators
+
它不会构造内存列表并在返回之前耗尽所有输入迭代器; 相反,元组仅在被请求时才被构造和返回。 (这种行为的技术术语是 [https://en.wikipedia.org/wiki/Lazy_evaluation 懒惰评估] 。)
before returning; instead tuples are constructed and returned only if they're
 
requested. (The technical term for this behaviour is [https://en.wikipedia.org/wiki/Lazy_evaluation lazy evaluation].)
 
  
This iterator is intended to be used with iterables that are all of the same
+
此迭代器旨在与长度相同的可迭代对象一起使用。 如果可迭代对象的长度不同,则生成的流将与最短的可迭代对象长度相同。
length. If the iterables are of different lengths, the resulting stream will be
 
the same length as the shortest iterable.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第935行: 第707行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>zip(['a', 'b'], (1, 2, 3)) =&gt;
+
<syntaxhighlight lang="python3">zip(['a', 'b'], (1, 2, 3)) =>
   ('a', 1), ('b', 2)</pre>
+
   ('a', 1), ('b', 2)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
You should avoid doing this, though, because an element may be taken from the
+
但是,您应该避免这样做,因为元素可能会从较长的迭代器中取出并被丢弃。 这意味着您不能继续使用迭代器,因为您可能会跳过丢弃的元素。
longer iterators and discarded. This means you can't go on to use the iterators
 
further because you risk skipping a discarded element.
 
  
  
第949行: 第719行:
 
<div id="the-itertools-module" class="section">
 
<div id="the-itertools-module" class="section">
  
== The itertools module ==
+
== itertools 模块 ==
  
The [[../../library/itertools#module-itertools|<code>itertools</code>]] module contains a number of commonly-used iterators as well
+
[[../../library/itertools#module-itertools|itertools]] 模块包含许多常用的迭代器以及用于组合多个迭代器的函数。 本节将通过展示小例子来介绍模块的内容。
as functions for combining several iterators. This section will introduce the
 
module's contents by showing small examples.
 
  
The module's functions fall into a few broad classes:
+
该模块的功能分为几个大类:
  
* Functions that create a new iterator based on an existing iterator.
+
* 基于现有迭代器创建新迭代器的函数。
* Functions for treating an iterator's elements as function arguments.
+
* 将迭代器的元素视为函数参数的函数。
* Functions for selecting portions of an iterator's output.
+
* 用于选择迭代器输出部分的函数。
* A function for grouping an iterator's output.
+
* 用于对迭代器的输出进行分组的函数。
  
 
<div id="creating-new-iterators" class="section">
 
<div id="creating-new-iterators" class="section">
  
=== Creating new iterators ===
+
=== 创建新的迭代器 ===
  
[[../../library/itertools#itertools|<code>itertools.count(start, step)</code>]] returns an infinite
+
[[../../library/itertools#itertools|itertools.count(start, step)]] 返回均匀间隔值的无限流。 您可以选择提供起始编号(默认为 0)和数字之间的间隔(默认为 1):
stream of evenly spaced values. You can optionally supply the starting number,
 
which defaults to 0, and the interval between numbers, which defaults to 1:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第974行: 第740行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.count() =&gt;
+
<syntaxhighlight lang="python3">itertools.count() =>
 
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
 
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
itertools.count(10) =&gt;
+
itertools.count(10) =>
 
   10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...
 
   10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...
itertools.count(10, 5) =&gt;
+
itertools.count(10, 5) =>
   10, 15, 20, 25, 30, 35, 40, 45, 50, 55, ...</pre>
+
   10, 15, 20, 25, 30, 35, 40, 45, 50, 55, ...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/itertools#itertools|<code>itertools.cycle(iter)</code>]] saves a copy of the contents of
+
[[../../library/itertools#itertools|itertools.cycle(iter)]] 保存提供的可迭代内容的副本并返回一个新的迭代器,该迭代器从头到尾返回其元素。 新的迭代器将无限重复这些元素。
a provided iterable and returns a new iterator that returns its elements from
 
first to last. The new iterator will repeat these elements infinitely.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第992行: 第756行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.cycle([1, 2, 3, 4, 5]) =&gt;
+
<syntaxhighlight lang="python3">itertools.cycle([1, 2, 3, 4, 5]) =>
   1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...</pre>
+
   1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../library/itertools.html#itertools.repeat|<code>itertools.repeat(elem, [n])</code>]] returns the provided
+
[[../library/itertools.html#itertools.repeat|itertools.repeat(elem, [n])]] 返回提供的元素 ''n'' 次,或者如果没有提供 ''n'' 则无限返回元素。
element ''n'' times, or returns the element endlessly if ''n'' is not provided.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,005行: 第768行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.repeat('abc') =&gt;
+
<syntaxhighlight lang="python3">itertools.repeat('abc') =>
 
   abc, abc, abc, abc, abc, abc, abc, abc, abc, abc, ...
 
   abc, abc, abc, abc, abc, abc, abc, abc, abc, abc, ...
itertools.repeat('abc', 5) =&gt;
+
itertools.repeat('abc', 5) =>
   abc, abc, abc, abc, abc</pre>
+
   abc, abc, abc, abc, abc</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/itertools#itertools|<code>itertools.chain(iterA, iterB, ...)</code>]] takes an arbitrary
+
[[../../library/itertools#itertools|itertools.chain(iterA, iterB, ...)]] 将任意数量的迭代器作为输入,并返回第一个迭代器的所有元素,然后是第二个迭代器的所有元素,依此类推,直到所有可迭代对象都已用尽。
number of iterables as input, and returns all the elements of the first
 
iterator, then all the elements of the second, and so on, until all of the
 
iterables have been exhausted.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,022行: 第782行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.chain(['a', 'b', 'c'], (1, 2, 3)) =&gt;
+
<syntaxhighlight lang="python3">itertools.chain(['a', 'b', 'c'], (1, 2, 3)) =>
   a, b, c, 1, 2, 3</pre>
+
   a, b, c, 1, 2, 3</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../library/itertools.html#itertools.islice|<code>itertools.islice(iter, [start], stop, [step])</code>]] returns
+
[[../library/itertools.html#itertools.islice|itertools.islice(iter, [start], stop, [step])]] 返回一个流,它是迭代器的一个切片。 使用单个 ''stop'' 参数,它将返回第一个 ''stop'' 元素。 如果您提供起始索引,您将获得 ''stop-start'' 元素,如果您为 ''step'' 提供值,则将相应地跳过元素。 与 Python 的字符串和列表切片不同,您不能对 ''start''''stop'' ''step'' 使用负值。
a stream that's a slice of the iterator. With a single ''stop'' argument, it
 
will return the first ''stop'' elements. If you supply a starting index, you'll
 
get ''stop-start'' elements, and if you supply a value for ''step'', elements
 
will be skipped accordingly. Unlike Python's string and list slicing, you can't
 
use negative values for ''start'', ''stop'', or ''step''.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,039行: 第794行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.islice(range(10), 8) =&gt;
+
<syntaxhighlight lang="python3">itertools.islice(range(10), 8) =>
 
   0, 1, 2, 3, 4, 5, 6, 7
 
   0, 1, 2, 3, 4, 5, 6, 7
itertools.islice(range(10), 2, 8) =&gt;
+
itertools.islice(range(10), 2, 8) =>
 
   2, 3, 4, 5, 6, 7
 
   2, 3, 4, 5, 6, 7
itertools.islice(range(10), 2, 8, 2) =&gt;
+
itertools.islice(range(10), 2, 8, 2) =>
   2, 4, 6</pre>
+
   2, 4, 6</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../library/itertools.html#itertools.tee|<code>itertools.tee(iter, [n])</code>]] replicates an iterator; it
+
[[../library/itertools.html#itertools.tee|itertools.tee(iter, [n])]] 复制一个迭代器; 它返回 ''n'' 个独立迭代器,这些迭代器都将返回源迭代器的内容。 如果您不为 ''n'' 提供值,则默认值为 2。 复制迭代器需要保存源迭代器的一些内容,因此如果迭代器很大并且新迭代器之一比其他迭代器消耗更多,这会消耗大量内存。
returns ''n'' independent iterators that will all return the contents of the
 
source iterator.
 
If you don't supply a value for ''n'', the default is 2. Replicating iterators
 
requires saving some of the contents of the source iterator, so this can consume
 
significant memory if the iterator is large and one of the new iterators is
 
consumed more than the others.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,061行: 第810行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.tee( itertools.count() ) =&gt;
+
<syntaxhighlight lang="python3">itertools.tee( itertools.count() ) =>
 
   iterA, iterB
 
   iterA, iterB
  
where iterA -&gt;
+
where iterA ->
 
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
 
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
  
and  iterB -&gt;
+
and  iterB ->
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...</pre>
+
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...</syntaxhighlight>
  
 
</div>
 
</div>
第1,077行: 第826行:
 
<div id="calling-functions-on-elements" class="section">
 
<div id="calling-functions-on-elements" class="section">
  
=== Calling functions on elements ===
+
=== 在元素上调用函数 ===
  
The [[../../library/operator#module-operator|<code>operator</code>]] module contains a set of functions corresponding to Python's
+
[[../../library/operator#module-operator|operator]] 模块包含一组对应于 Python 运算符的函数。 一些示例是 [[../../library/operator#operator|operator.add(a, b)]](添加两个值)、[[../../library/operator#operator|operator.ne(a, b)]](与 <code>a != b</code> 相同)和 [ X117X]operator.attrgetter('id')(返回一个获取 <code>.id</code> 属性的可调用对象)。
operators. Some examples are [[../../library/operator#operator|<code>operator.add(a, b)</code>]] (adds
 
two values), [[../../library/operator#operator|<code>operator.ne(a, b)</code>]] (same as <code>a != b</code>), and
 
[[../../library/operator#operator|<code>operator.attrgetter('id')</code>]]
 
(returns a callable that fetches the <code>.id</code> attribute).
 
  
[[../../library/itertools#itertools|<code>itertools.starmap(func, iter)</code>]] assumes that the
+
[[../../library/itertools#itertools|itertools.starmap(func, iter)]] 假设可迭代对象将返回一个元组流,并使用这些元组作为参数调用 ''func''
iterable will return a stream of tuples, and calls ''func'' using these tuples as
 
the arguments:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,093行: 第836行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.starmap(os.path.join,
+
<syntaxhighlight lang="python3">itertools.starmap(os.path.join,
 
                   [('/bin', 'python'), ('/usr', 'bin', 'java'),
 
                   [('/bin', 'python'), ('/usr', 'bin', 'java'),
 
                   ('/usr', 'bin', 'perl'), ('/usr', 'bin', 'ruby')])
 
                   ('/usr', 'bin', 'perl'), ('/usr', 'bin', 'ruby')])
=&gt;
+
=>
   /bin/python, /usr/bin/java, /usr/bin/perl, /usr/bin/ruby</pre>
+
   /bin/python, /usr/bin/java, /usr/bin/perl, /usr/bin/ruby</syntaxhighlight>
  
 
</div>
 
</div>
第1,106行: 第849行:
 
<div id="selecting-elements" class="section">
 
<div id="selecting-elements" class="section">
  
=== Selecting elements ===
+
=== 选择元素 ===
  
Another group of functions chooses a subset of an iterator's elements based on a
+
另一组函数根据谓词选择迭代器元素的子集。
predicate.
 
  
[[../../library/itertools#itertools|<code>itertools.filterfalse(predicate, iter)</code>]] is the
+
[[../../library/itertools#itertools|itertools.filterfalse(predicate, iter)]] [[../../library/functions#filter|filter()]] 相反,返回谓词返回 false 的所有元素:
opposite of [[../../library/functions#filter|<code>filter()</code>]], returning all elements for which the predicate
 
returns false:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,119行: 第859行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.filterfalse(is_even, itertools.count()) =&gt;
+
<syntaxhighlight lang="python3">itertools.filterfalse(is_even, itertools.count()) =>
   1, 3, 5, 7, 9, 11, 13, 15, ...</pre>
+
   1, 3, 5, 7, 9, 11, 13, 15, ...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/itertools#itertools|<code>itertools.takewhile(predicate, iter)</code>]] returns
+
[[../../library/itertools#itertools|itertools.takewhile(predicate, iter)]] 返回元素,只要谓词返回 true。 一旦谓词返回 false,迭代器将发出结果结束的信号。
elements for as long as the predicate returns true. Once the predicate returns
 
false, the iterator will signal the end of its results.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,133行: 第871行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def less_than_10(x):
+
<syntaxhighlight lang="python3">def less_than_10(x):
     return x &lt; 10
+
     return x < 10
  
itertools.takewhile(less_than_10, itertools.count()) =&gt;
+
itertools.takewhile(less_than_10, itertools.count()) =>
 
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9
 
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  
itertools.takewhile(is_even, itertools.count()) =&gt;
+
itertools.takewhile(is_even, itertools.count()) =>
   0</pre>
+
   0</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/itertools#itertools|<code>itertools.dropwhile(predicate, iter)</code>]] discards
+
[[../../library/itertools#itertools|itertools.dropwhile(predicate, iter)]] 在谓词返回真时丢弃元素,然后返回可迭代结果的其余部分。
elements while the predicate returns true, and then returns the rest of the
 
iterable's results.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,153行: 第889行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.dropwhile(less_than_10, itertools.count()) =&gt;
+
<syntaxhighlight lang="python3">itertools.dropwhile(less_than_10, itertools.count()) =>
 
   10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...
 
   10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...
  
itertools.dropwhile(is_even, itertools.count()) =&gt;
+
itertools.dropwhile(is_even, itertools.count()) =>
   1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...</pre>
+
   1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/itertools#itertools|<code>itertools.compress(data, selectors)</code>]] takes two
+
[[../../library/itertools#itertools|itertools.compress(data, selectors)]] 接受两个迭代器并只返回 ''data'' ''selectors'' 的对应元素为真的那些元素,只要有一个就停止筋疲力尽:
iterators and returns only those elements of ''data'' for which the corresponding
 
element of ''selectors'' is true, stopping whenever either one is exhausted:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,170行: 第904行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.compress([1, 2, 3, 4, 5], [True, True, False, False, True]) =&gt;
+
<syntaxhighlight lang="python3">itertools.compress([1, 2, 3, 4, 5], [True, True, False, False, True]) =>
   1, 2, 5</pre>
+
   1, 2, 5</syntaxhighlight>
  
 
</div>
 
</div>
第1,180行: 第914行:
 
<div id="combinatoric-functions" class="section">
 
<div id="combinatoric-functions" class="section">
  
=== Combinatoric functions ===
+
=== 组合函数 ===
  
The [[../../library/itertools#itertools|<code>itertools.combinations(iterable, r)</code>]]
+
[[../../library/itertools#itertools|itertools.combinations(iterable, r)]] 返回一个迭代器,给出 ''iterable'' 中包含的元素的所有可能的 ''r'' 元组组合。
returns an iterator giving all possible ''r''-tuple combinations of the
 
elements contained in ''iterable''.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,190行: 第922行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.combinations([1, 2, 3, 4, 5], 2) =&gt;
+
<syntaxhighlight lang="python3">itertools.combinations([1, 2, 3, 4, 5], 2) =>
 
   (1, 2), (1, 3), (1, 4), (1, 5),
 
   (1, 2), (1, 3), (1, 4), (1, 5),
 
   (2, 3), (2, 4), (2, 5),
 
   (2, 3), (2, 4), (2, 5),
第1,196行: 第928行:
 
   (4, 5)
 
   (4, 5)
  
itertools.combinations([1, 2, 3, 4, 5], 3) =&gt;
+
itertools.combinations([1, 2, 3, 4, 5], 3) =>
 
   (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5),
 
   (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5),
 
   (2, 3, 4), (2, 3, 5), (2, 4, 5),
 
   (2, 3, 4), (2, 3, 5), (2, 4, 5),
   (3, 4, 5)</pre>
+
   (3, 4, 5)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The elements within each tuple remain in the same order as
+
每个元组中的元素保持与 ''iterable'' 返回它们相同的顺序。 例如,在上述示例中,数字 1 始终位于 2、3、4 或 5 之前。 一个类似的函数,[[../../library/itertools#itertools|itertools.permutations(iterable, r=None)]],移除了这个对顺序的限制,返回所有可能的长度为 ''r'' 的排列:
''iterable'' returned them. For example, the number 1 is always before
 
2, 3, 4, or 5 in the examples above. A similar function,
 
[[../../library/itertools#itertools|<code>itertools.permutations(iterable, r=None)</code>]],
 
removes this constraint on the order, returning all possible
 
arrangements of length ''r'':
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,215行: 第942行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.permutations([1, 2, 3, 4, 5], 2) =&gt;
+
<syntaxhighlight lang="python3">itertools.permutations([1, 2, 3, 4, 5], 2) =>
 
   (1, 2), (1, 3), (1, 4), (1, 5),
 
   (1, 2), (1, 3), (1, 4), (1, 5),
 
   (2, 1), (2, 3), (2, 4), (2, 5),
 
   (2, 1), (2, 3), (2, 4), (2, 5),
第1,222行: 第949行:
 
   (5, 1), (5, 2), (5, 3), (5, 4)
 
   (5, 1), (5, 2), (5, 3), (5, 4)
  
itertools.permutations([1, 2, 3, 4, 5]) =&gt;
+
itertools.permutations([1, 2, 3, 4, 5]) =>
 
   (1, 2, 3, 4, 5), (1, 2, 3, 5, 4), (1, 2, 4, 3, 5),
 
   (1, 2, 3, 4, 5), (1, 2, 3, 5, 4), (1, 2, 4, 3, 5),
 
   ...
 
   ...
   (5, 4, 3, 2, 1)</pre>
+
   (5, 4, 3, 2, 1)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
If you don't supply a value for ''r'' the length of the iterable is used,
+
如果您不为 ''r'' 提供值,则使用可迭代的长度,这意味着所有元素都被置换。
meaning that all the elements are permuted.
 
  
Note that these functions produce all of the possible combinations by
+
请注意,这些函数按位置生成所有可能的组合,并且不需要 ''iterable'' 的内容是唯一的:
position and don't require that the contents of ''iterable'' are unique:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,240行: 第965行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.permutations('aba', 3) =&gt;
+
<syntaxhighlight lang="python3">itertools.permutations('aba', 3) =>
 
   ('a', 'b', 'a'), ('a', 'a', 'b'), ('b', 'a', 'a'),
 
   ('a', 'b', 'a'), ('a', 'a', 'b'), ('b', 'a', 'a'),
   ('b', 'a', 'a'), ('a', 'a', 'b'), ('a', 'b', 'a')</pre>
+
   ('b', 'a', 'a'), ('a', 'a', 'b'), ('a', 'b', 'a')</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The identical tuple <code>('a', 'a', 'b')</code> occurs twice, but the two 'a'
+
相同的元组 <code>('a', 'a', 'b')</code> 出现了两次,但两个 'a' 字符串来自不同的位置。
strings came from different positions.
 
  
The [[../../library/itertools#itertools|<code>itertools.combinations_with_replacement(iterable, r)</code>]]
+
[[../../library/itertools#itertools|itertools.combinations_with_replacement(iterable, r)]] 函数放宽了不同的约束:元素可以在单个元组中重复。 从概念上讲,为每个元组的第一个位置选择一个元素,然后在选择第二个元素之前替换它。
function relaxes a different constraint: elements can be repeated
 
within a single tuple. Conceptually an element is selected for the
 
first position of each tuple and then is replaced before the second
 
element is selected.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,260行: 第980行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.combinations_with_replacement([1, 2, 3, 4, 5], 2) =&gt;
+
<syntaxhighlight lang="python3">itertools.combinations_with_replacement([1, 2, 3, 4, 5], 2) =>
 
   (1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
 
   (1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
 
   (2, 2), (2, 3), (2, 4), (2, 5),
 
   (2, 2), (2, 3), (2, 4), (2, 5),
 
   (3, 3), (3, 4), (3, 5),
 
   (3, 3), (3, 4), (3, 5),
 
   (4, 4), (4, 5),
 
   (4, 4), (4, 5),
   (5, 5)</pre>
+
   (5, 5)</syntaxhighlight>
  
 
</div>
 
</div>
第1,274行: 第994行:
 
<div id="grouping-elements" class="section">
 
<div id="grouping-elements" class="section">
  
=== Grouping elements ===
+
=== 分组元素 ===
  
The last function I'll discuss, [[../../library/itertools#itertools|<code>itertools.groupby(iter, key_func=None)</code>]], is the most complicated. <code>key_func(elem)</code> is a function
+
我将讨论的最后一个函数 [[../../library/itertools#itertools|itertools.groupby(iter, key_func=None)]] 是最复杂的。 <code>key_func(elem)</code> 是一个函数,可以为迭代返回的每个元素计算一个键值。 如果您不提供键函数,键就是每个元素本身。
that can compute a key value for each element returned by the iterable. If you
 
don't supply a key function, the key is simply each element itself.
 
  
[[../../library/itertools#itertools|<code>groupby()</code>]] collects all the consecutive elements from the
+
[[../../library/itertools#itertools|groupby()]] 从底层迭代中收集所有具有相同键值的连续元素,并返回一个包含键值和具有该键的元素的迭代器的 2 元组流。
underlying iterable that have the same key value, and returns a stream of
 
2-tuples containing a key value and an iterator for the elements with that key.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,288行: 第1,004行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>city_list = [('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL'),
+
<syntaxhighlight lang="python3">city_list = [('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL'),
 
             ('Anchorage', 'AK'), ('Nome', 'AK'),
 
             ('Anchorage', 'AK'), ('Nome', 'AK'),
 
             ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ'),
 
             ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ'),
第1,297行: 第1,013行:
 
     return city_state[1]
 
     return city_state[1]
  
itertools.groupby(city_list, get_state) =&gt;
+
itertools.groupby(city_list, get_state) =>
 
   ('AL', iterator-1),
 
   ('AL', iterator-1),
 
   ('AK', iterator-2),
 
   ('AK', iterator-2),
第1,303行: 第1,019行:
  
 
where
 
where
iterator-1 =&gt;
+
iterator-1 =>
 
   ('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL')
 
   ('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL')
iterator-2 =&gt;
+
iterator-2 =>
 
   ('Anchorage', 'AK'), ('Nome', 'AK')
 
   ('Anchorage', 'AK'), ('Nome', 'AK')
iterator-3 =&gt;
+
iterator-3 =>
   ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ')</pre>
+
   ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ')</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../../library/itertools#itertools|<code>groupby()</code>]] assumes that the underlying iterable's contents will
+
[[../../library/itertools#itertools|groupby()]] 假设底层迭代的内容已经根据键进行了排序。 请注意,返回的迭代器也使用底层迭代器,因此您必须在请求 iterator-2 及其对应的 key 之前使用 iterator-1 的结果。
already be sorted based on the key. Note that the returned iterators also use
 
the underlying iterable, so you have to consume the results of iterator-1 before
 
requesting iterator-2 and its corresponding key.
 
  
  
第1,324行: 第1,037行:
 
<div id="the-functools-module" class="section">
 
<div id="the-functools-module" class="section">
  
== The functools module ==
+
== 功能工具模块 ==
  
The [[../../library/functools#module-functools|<code>functools</code>]] module in Python 2.5 contains some higher-order functions.
+
Python 2.5 中的 [[../../library/functools#module-functools|functools]] 模块包含一些高阶函数。 '''高阶函数''' 将一个或多个函数作为输入并返回一个新函数。 该模块中最有用的工具是 [[../../library/functools#functools|functools.partial()]] 函数。
A '''higher-order function''' takes one or more functions as input and returns a
 
new function. The most useful tool in this module is the
 
[[../../library/functools#functools|<code>functools.partial()</code>]] function.
 
  
For programs written in a functional style, you'll sometimes want to construct
+
对于以函数式风格编写的程序,您有时会希望构建填充了一些参数的现有函数的变体。 考虑一个 Python 函数 <code>f(a, b, c)</code>; 你可能希望创建一个新的函数 <code>g(b, c)</code> 相当于 <code>f(1, b, c)</code>; 您正在为 <code>f()</code> 的参数之一填充值。 这称为“部分功能应用”。
variants of existing functions that have some of the parameters filled in.
 
Consider a Python function <code>f(a, b, c)</code>; you may wish to create a new function
 
<code>g(b, c)</code> that's equivalent to <code>f(1, b, c)</code>; you're filling in a value for
 
one of <code>f()</code>'s parameters. This is called &quot;partial function application&quot;.
 
  
The constructor for [[../../library/functools#functools|<code>partial()</code>]] takes the arguments
+
[[../../library/functools#functools|partial()]] 的构造函数采用参数 <code>(function, arg1, arg2, ..., kwarg1=value1, kwarg2=value2)</code>。 结果对象是可调用的,因此您可以调用它来使用填充的参数调用 <code>function</code>
<code>(function, arg1, arg2, ..., kwarg1=value1, kwarg2=value2)</code>. The resulting
 
object is callable, so you can just call it to invoke <code>function</code> with the
 
filled-in arguments.
 
  
Here's a small but realistic example:
+
这是一个小而现实的例子:
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,348行: 第1,051行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>import functools
+
<syntaxhighlight lang="python3">import functools
  
 
def log(message, subsystem):
 
def log(message, subsystem):
     &quot;&quot;&quot;Write the contents of 'message' to the specified subsystem.&quot;&quot;&quot;
+
     """Write the contents of 'message' to the specified subsystem."""
 
     print('%s: %s' % (subsystem, message))
 
     print('%s: %s' % (subsystem, message))
 
     ...
 
     ...
  
 
server_log = functools.partial(log, subsystem='server')
 
server_log = functools.partial(log, subsystem='server')
server_log('Unable to open socket')</pre>
+
server_log('Unable to open socket')</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
[[../library/functools.html#functools.reduce|<code>functools.reduce(func, iter, [initial_value])</code>]]
+
[[../library/functools.html#functools.reduce|functools.reduce(func, iter, [initial_value])]] 累积对所有可迭代元素执行操作,因此不能应用于无限可迭代元素。 ''func'' 必须是一个接受两个元素并返回一个值的函数。 [[../../library/functools#functools|functools.reduce()]] 取迭代器返回的前两个元素 A B 并计算 <code>func(A, B)</code>。 然后它请求第三个元素 C,计算 <code>func(func(A, B), C)</code>,将此结果与返回的第四个元素组合,并继续直到迭代用完。 如果可迭代对象根本没有返回值,则会引发 [[../../library/exceptions#TypeError|TypeError]] 异常。 如果提供了初始值,则将其用作起点,并且 <code>func(initial_value, A)</code> 是第一个计算。
cumulatively performs an operation on all the iterable's elements and,
 
therefore, can't be applied to infinite iterables. ''func'' must be a function
 
that takes two elements and returns a single value. [[../../library/functools#functools|<code>functools.reduce()</code>]]
 
takes the first two elements A and B returned by the iterator and calculates
 
<code>func(A, B)</code>. It then requests the third element, C, calculates
 
<code>func(func(A, B), C)</code>, combines this result with the fourth element returned,
 
and continues until the iterable is exhausted. If the iterable returns no
 
values at all, a [[../../library/exceptions#TypeError|<code>TypeError</code>]] exception is raised. If the initial value is
 
supplied, it's used as a starting point and <code>func(initial_value, A)</code> is the
 
first calculation.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,377行: 第1,070行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; import operator, functools
+
<syntaxhighlight lang="python3">>>> import operator, functools
&gt;&gt;&gt; functools.reduce(operator.concat, ['A', 'BB', 'C'])
+
>>> functools.reduce(operator.concat, ['A', 'BB', 'C'])
 
'ABBC'
 
'ABBC'
&gt;&gt;&gt; functools.reduce(operator.concat, [])
+
>>> functools.reduce(operator.concat, [])
 
Traceback (most recent call last):
 
Traceback (most recent call last):
 
   ...
 
   ...
 
TypeError: reduce() of empty sequence with no initial value
 
TypeError: reduce() of empty sequence with no initial value
&gt;&gt;&gt; functools.reduce(operator.mul, [1, 2, 3], 1)
+
>>> functools.reduce(operator.mul, [1, 2, 3], 1)
 
6
 
6
&gt;&gt;&gt; functools.reduce(operator.mul, [], 1)
+
>>> functools.reduce(operator.mul, [], 1)
1</pre>
+
1</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
If you use [[../../library/operator#operator|<code>operator.add()</code>]] with [[../../library/functools#functools|<code>functools.reduce()</code>]], you'll add up all the
+
如果您将 [[../../library/operator#operator|operator.add()]] [[../../library/functools#functools|functools.reduce()]] 一起使用,您将把可迭代对象的所有元素相加。 这种情况非常常见,以至于有一个特殊的内置函数 [[../../library/functions#sum|sum()]] 来计算它:
elements of the iterable. This case is so common that there's a special
 
built-in called [[../../library/functions#sum|<code>sum()</code>]] to compute it:
 
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第1,400行: 第1,091行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; import functools, operator
+
<syntaxhighlight lang="python">>>> import functools, operator
&gt;&gt;&gt; functools.reduce(operator.add, [1, 2, 3, 4], 0)
+
>>> functools.reduce(operator.add, [1, 2, 3, 4], 0)
 
10
 
10
&gt;&gt;&gt; sum([1, 2, 3, 4])
+
>>> sum([1, 2, 3, 4])
 
10
 
10
&gt;&gt;&gt; sum([])
+
>>> sum([])
0</pre>
+
0</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
For many uses of [[../../library/functools#functools|<code>functools.reduce()</code>]], though, it can be clearer to just
+
但是,对于 [[../../library/functools#functools|functools.reduce()]] 的许多用途,只需编写明显的 [[../../reference/compound_stmts#for|for]] 循环会更清晰:
write the obvious [[../../reference/compound_stmts#for|<code>for</code>]] loop:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,418行: 第1,108行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>import functools
+
<syntaxhighlight lang="python3">import functools
 
# Instead of:
 
# Instead of:
 
product = functools.reduce(operator.mul, [1, 2, 3], 1)
 
product = functools.reduce(operator.mul, [1, 2, 3], 1)
第1,425行: 第1,115行:
 
product = 1
 
product = 1
 
for i in [1, 2, 3]:
 
for i in [1, 2, 3]:
     product *= i</pre>
+
     product *= i</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
A related function is [[../../library/itertools#itertools|<code>itertools.accumulate(iterable, func=operator.add)</code>]]. It performs the same calculation, but instead of
+
一个相关的函数是 [[../../library/itertools#itertools|itertools.accumulate(iterable, func=operator.add)]]。 它执行相同的计算,但不是只返回最终结果,<code>accumulate()</code> 返回一个迭代器,该迭代器也产生每个部分结果:
returning only the final result, <code>accumulate()</code> returns an iterator that
 
also yields each partial result:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,438行: 第1,126行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>itertools.accumulate([1, 2, 3, 4, 5]) =&gt;
+
<syntaxhighlight lang="python3">itertools.accumulate([1, 2, 3, 4, 5]) =>
 
   1, 3, 6, 10, 15
 
   1, 3, 6, 10, 15
  
itertools.accumulate([1, 2, 3, 4, 5], operator.mul) =&gt;
+
itertools.accumulate([1, 2, 3, 4, 5], operator.mul) =>
   1, 2, 6, 24, 120</pre>
+
   1, 2, 6, 24, 120</syntaxhighlight>
  
 
</div>
 
</div>
第1,449行: 第1,137行:
 
<div id="the-operator-module" class="section">
 
<div id="the-operator-module" class="section">
  
=== The operator module ===
+
=== 操作员模块 ===
  
The [[../../library/operator#module-operator|<code>operator</code>]] module was mentioned earlier. It contains a set of
+
[[../../library/operator#module-operator|operator]] 模块前面已经提到过。 它包含一组对应于 Python 操作符的函数。 这些函数在函数式代码中通常很有用,因为它们使您无需编写执行单个操作的琐碎函数。
functions corresponding to Python's operators. These functions are often useful
 
in functional-style code because they save you from writing trivial functions
 
that perform a single operation.
 
  
Some of the functions in this module are:
+
该模块中的一些功能是:
  
* Math operations: <code>add()</code>, <code>sub()</code>, <code>mul()</code>, <code>floordiv()</code>, <code>abs()</code>, ...
+
* 数学运算:<code>add()</code><code>sub()</code><code>mul()</code><code>floordiv()</code><code>abs()</code>、……
* Logical operations: <code>not_()</code>, <code>truth()</code>.
+
* 逻辑运算:<code>not_()</code><code>truth()</code>
* Bitwise operations: <code>and_()</code>, <code>or_()</code>, <code>invert()</code>.
+
* 按位运算:<code>and_()</code><code>or_()</code><code>invert()</code>
* Comparisons: <code>eq()</code>, <code>ne()</code>, <code>lt()</code>, <code>le()</code>, <code>gt()</code>, and <code>ge()</code>.
+
* 比较:<code>eq()</code><code>ne()</code><code>lt()</code><code>le()</code><code>gt()</code><code>ge()</code>
* Object identity: <code>is_()</code>, <code>is_not()</code>.
+
* 对象标识:<code>is_()</code><code>is_not()</code>
  
Consult the operator module's documentation for a complete list.
+
有关完整列表,请参阅操作员模块的文档。
  
  
第1,472行: 第1,157行:
 
<div id="small-functions-and-the-lambda-expression" class="section">
 
<div id="small-functions-and-the-lambda-expression" class="section">
  
== Small functions and the lambda expression ==
+
== 小函数和 lambda 表达式 ==
  
When writing functional-style programs, you'll often need little functions that
+
在编写函数式程序时,您通常需要一些充当谓词或以某种方式组合元素的函数。
act as predicates or that combine elements in some way.
 
  
If there's a Python built-in or a module function that's suitable, you don't
+
如果有合适的 Python 内置函数或模块函数,则根本不需要定义新函数:
need to define a new function at all:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,484行: 第1,167行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>stripped_lines = [line.strip() for line in lines]
+
<syntaxhighlight lang="python3">stripped_lines = [line.strip() for line in lines]
existing_files = filter(os.path.exists, file_list)</pre>
+
existing_files = filter(os.path.exists, file_list)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
If the function you need doesn't exist, you need to write it. One way to write
+
如果您需要的函数不存在,则需要编写它。 编写小函数的一种方法是使用 [[../../reference/expressions#lambda|lambda]] 表达式。 <code>lambda</code> 接受多个参数和组合这些参数的表达式,并创建一个返回表达式值的匿名函数:
small functions is to use the [[../../reference/expressions#lambda|<code>lambda</code>]] expression. <code>lambda</code> takes a
 
number of parameters and an expression combining these parameters, and creates
 
an anonymous function that returns the value of the expression:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,499行: 第1,179行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>adder = lambda x, y: x+y
+
<syntaxhighlight lang="python3">adder = lambda x, y: x+y
  
print_assign = lambda name, value: name + '=' + str(value)</pre>
+
print_assign = lambda name, value: name + '=' + str(value)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
An alternative is to just use the <code>def</code> statement and define a function in the
+
另一种方法是使用 <code>def</code> 语句并以通常的方式定义函数:
usual way:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,513行: 第1,192行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def adder(x, y):
+
<syntaxhighlight lang="python3">def adder(x, y):
 
     return x + y
 
     return x + y
  
 
def print_assign(name, value):
 
def print_assign(name, value):
     return name + '=' + str(value)</pre>
+
     return name + '=' + str(value)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Which alternative is preferable? That's a style question; my usual course is to
+
哪个替代方案更可取? 这是一个风格问题; 我通常的做法是避免使用 <code>lambda</code>
avoid using <code>lambda</code>.
 
  
One reason for my preference is that <code>lambda</code> is quite limited in the
+
我偏爱的原因之一是 <code>lambda</code> 在它可以定义的功能方面非常有限。 结果必须可以作为单个表达式进行计算,这意味着您不能进行多路 <code>if... elif... else</code> 比较或 <code>try... except</code> 语句。 如果您试图在 <code>lambda</code> 语句中做太多事情,最终会得到一个难以阅读的过于复杂的表达式。 快,下面的代码在做什么?
functions it can define. The result has to be computable as a single
 
expression, which means you can't have multiway <code>if... elif... else</code>
 
comparisons or <code>try... except</code> statements. If you try to do too much in a
 
<code>lambda</code> statement, you'll end up with an overly complicated expression that's
 
hard to read. Quick, what's the following code doing?
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,536行: 第1,209行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>import functools
+
<syntaxhighlight lang="python3">import functools
total = functools.reduce(lambda a, b: (0, a[1] + b[1]), items)[1]</pre>
+
total = functools.reduce(lambda a, b: (0, a[1] + b[1]), items)[1]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
You can figure it out, but it takes time to disentangle the expression to figure
+
您可以弄清楚,但需要时间来理清表达式以弄清楚发生了什么。 使用简短的嵌套 <code>def</code> 语句会使事情变得更好:
out what's going on. Using a short nested <code>def</code> statements makes things a
 
little bit better:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,550行: 第1,221行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>import functools
+
<syntaxhighlight lang="python3">import functools
 
def combine(a, b):
 
def combine(a, b):
 
     return 0, a[1] + b[1]
 
     return 0, a[1] + b[1]
  
total = functools.reduce(combine, items)[1]</pre>
+
total = functools.reduce(combine, items)[1]</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
But it would be best of all if I had simply used a <code>for</code> loop:
+
但如果我只是使用 <code>for</code> 循环,那将是最好的:
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,565行: 第1,236行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>total = 0
+
<syntaxhighlight lang="python3">total = 0
 
for a, b in items:
 
for a, b in items:
     total += b</pre>
+
     total += b</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Or the [[../../library/functions#sum|<code>sum()</code>]] built-in and a generator expression:
+
或者 [[../../library/functions#sum|sum()]] 内置和生成器表达式:
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第1,578行: 第1,249行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>total = sum(b for a, b in items)</pre>
+
<syntaxhighlight lang="python3">total = sum(b for a, b in items)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Many uses of [[../../library/functools#functools|<code>functools.reduce()</code>]] are clearer when written as <code>for</code> loops.
+
[[../../library/functools#functools|functools.reduce()]] 的许多用途在编写为 <code>for</code> 循环时更加清晰。
  
Fredrik Lundh once suggested the following set of rules for refactoring uses of
+
Fredrik Lundh 曾经建议使用以下规则来重构 <code>lambda</code> 的使用:
<code>lambda</code>:
 
  
# Write a lambda function.
+
# 编写一个 lambda 函数。
# Write a comment explaining what the heck that lambda does.
+
# 写一条评论来解释 lambda 的作用。
# Study the comment for a while, and think of a name that captures the essence of the comment.
+
# 研究一下评论,然后想出一个能抓住评论本质的名字。
# Convert the lambda to a def statement, using that name.
+
# 使用该名称将 lambda 转换为 def 语句。
# Remove the comment.
+
# 删除评论。
  
I really like these rules, but you're free to disagree
+
我真的很喜欢这些规则,但你可以自由地不同意这种无 lambda 的风格是否更好。
about whether this lambda-free style is better.
 
  
  
第1,601行: 第1,270行:
 
<div id="revision-history-and-acknowledgements" class="section">
 
<div id="revision-history-and-acknowledgements" class="section">
  
== Revision History and Acknowledgements ==
+
== 修订历史和致谢 ==
  
The author would like to thank the following people for offering suggestions,
+
作者要感谢以下人员对本文的各种草稿提供建议、更正和帮助:Ian Bicking、Nick Coghlan、Nick Efford、Raymond Hettinger、Jim Jewett、Mike Krell、Leandro Lameiro、Jussi Salmela、Collin Winter,布莱克温顿。
corrections and assistance with various drafts of this article: Ian Bicking,
 
Nick Coghlan, Nick Efford, Raymond Hettinger, Jim Jewett, Mike Krell, Leandro
 
Lameiro, Jussi Salmela, Collin Winter, Blake Winton.
 
  
Version 0.1: posted June 30 2006.
+
0.1 版:2006 年 6 月 30 日发布。
  
Version 0.11: posted July 1 2006. Typo fixes.
+
0.11 版:2006 年 7 月 1 日发布。 错别字修复。
  
Version 0.2: posted July 10 2006. Merged genexp and listcomp sections into one.
+
0.2 版:2006 年 7 月 10 日发布。 将 genexp listcomp 部分合并为一个。 错别字修复。
Typo fixes.
 
  
Version 0.21: Added more references suggested on the tutor mailing list.
+
0.21 版:在导师邮件列表中添加了更多建议参考。
  
Version 0.30: Adds a section on the <code>functional</code> module written by Collin
+
0.30 版本:在 Collin Winter 编写的 <code>functional</code> 模块上添加了一个部分; 在操作员模块上添加了简短的部分; 其他一些编辑。
Winter; adds short section on the operator module; a few other edits.
 
  
  
第1,624行: 第1,288行:
 
<div id="references" class="section">
 
<div id="references" class="section">
  
== References ==
+
== 参考 ==
  
 
<div id="general" class="section">
 
<div id="general" class="section">
  
=== General ===
+
=== 一般 ===
  
'''Structure and Interpretation of Computer Programs''', by Harold Abelson and
+
'''计算机程序的结构和解释''' ,Harold Abelson Gerald Jay Sussman Julie Sussman 合着。 全文在 https://mitpress.mit.edu/sicp/。 在这本经典的计算机科学教科书中,第 2 章和第 3 章讨论了使用序列和流来组织程序内的数据流。 本书使用 Scheme 作为示例,但这些章节中描述的许多设计方法都适用于函数式 Python 代码。
Gerald Jay Sussman with Julie Sussman. Full text at
 
https://mitpress.mit.edu/sicp/. In this classic textbook of computer science,
 
chapters 2 and 3 discuss the use of sequences and streams to organize the data
 
flow inside a program. The book uses Scheme for its examples, but many of the
 
design approaches described in these chapters are applicable to functional-style
 
Python code.
 
  
http://www.defmacro.org/ramblings/fp.html: A general introduction to functional
+
http://www.defmacro.org/ramblings/fp.html:函数式编程的一般介绍,使用 Java 示例,并有冗长的历史介绍。
programming that uses Java examples and has a lengthy historical introduction.
 
  
https://en.wikipedia.org/wiki/Functional_programming: General Wikipedia entry
+
https://en.wikipedia.org/wiki/Functional_programming:描述函数式编程的一般维基百科条目。
describing functional programming.
 
  
https://en.wikipedia.org/wiki/Coroutine: Entry for coroutines.
+
https://en.wikipedia.org/wiki/Coroutine:协程入口。
  
https://en.wikipedia.org/wiki/Currying: Entry for the concept of currying.
+
https://en.wikipedia.org/wiki/Currying:柯里化概念的入口。
  
  
第1,652行: 第1,308行:
 
<div id="python-specific" class="section">
 
<div id="python-specific" class="section">
  
=== Python-specific ===
+
=== 特定于 Python ===
  
http://gnosis.cx/TPiP/: The first chapter of David Mertz's book
+
http://gnosis.cx/TPiP/:David Mertz 的书 Text Processing in Python 的第一章讨论了文本处理的函数式编程,在标题为“利用高阶文本处理中的函数”。
Text Processing in Python discusses functional programming
 
for text processing, in the section titled &quot;Utilizing Higher-Order Functions in
 
Text Processing&quot;.
 
  
Mertz also wrote a 3-part series of articles on functional programming
+
Mertz 还为 IBM DeveloperWorks 站点撰写了关于函数式编程的 3 部分系列文章; 见[https://developer.ibm.com/articles/l-prog/ 第1部分][https://developer.ibm.com/tutorials/l-prog2/ 第2部分][https://developer.ibm.com/tutorials/l-prog3/ 第3部分]
for IBM's DeveloperWorks site; see
 
[https://developer.ibm.com/articles/l-prog/ part 1],
 
[https://developer.ibm.com/tutorials/l-prog2/ part 2], and
 
[https://developer.ibm.com/tutorials/l-prog3/ part 3],
 
  
  
第1,669行: 第1,318行:
 
<div id="python-documentation" class="section">
 
<div id="python-documentation" class="section">
  
=== Python documentation ===
+
=== Python 文档 ===
  
Documentation for the [[../../library/itertools#module-itertools|<code>itertools</code>]] module.
+
[[../../library/itertools#module-itertools|itertools]] 模块的文档。
  
Documentation for the [[../../library/functools#module-functools|<code>functools</code>]] module.
+
[[../../library/functools#module-functools|functools]] 模块的文档。
  
Documentation for the [[../../library/operator#module-operator|<code>operator</code>]] module.
+
[[../../library/operator#module-operator|operator]] 模块的文档。
  
<span id="index-1" class="target"></span>[https://www.python.org/dev/peps/pep-0289 '''PEP 289''']: &quot;Generator Expressions&quot;
+
<span id="index-1" class="target"></span>[https://www.python.org/dev/peps/pep-0289 PEP 289]:“生成器表达式”
  
<span id="index-2" class="target"></span>[https://www.python.org/dev/peps/pep-0342 '''PEP 342''']: &quot;Coroutines via Enhanced Generators&quot; describes the new generator
+
<span id="index-2" class="target"></span>[https://www.python.org/dev/peps/pep-0342 PEP 342]:“Coroutines via Enhanced Generators”描述了 Python 2.5 中的新生成器特性。
features in Python 2.5.
 
  
  
第1,686行: 第1,334行:
  
 
</div>
 
</div>
 +
 +
</div>
 +
<div class="clearer">
 +
 +
  
 
</div>
 
</div>
  
[[Category:Python 3.9 中文文档]]
+
[[Category:Python 3.9 文档]]

2021年10月31日 (日) 04:50的最新版本

函数式编程HOWTO

作者
    1. 库克林

发布

0.32

在本文档中,我们将了解适合以函数式风格实现程序的 Python 特性。 在介绍了函数式编程的概念之后,我们将看看语言特性,例如 iterators 和 generators 以及相关的库模块,例如 itertoolsfunctools

介绍

本节解释函数式编程的基本概念; 如果您只是对了解 Python 语言功能感兴趣,请跳到下一部分 Iterators

编程语言支持以多种不同方式分解问题:

  • 大多数编程语言都是 过程化 :程序是指令列表,告诉计算机如何处理程序的输入。 C、Pascal 甚至 Unix shell 都是过程语言。
  • 声明性 语言中,您编写描述要解决的问题的规范,语言实现会弄清楚如何有效地执行计算。 SQL 是您最有可能熟悉的声明性语言; SQL 查询描述了您要检索的数据集,SQL 引擎决定是扫描表还是使用索引,应先执行哪些子条款等。
  • 面向对象的程序操作对象的集合。 对象具有内部状态并支持以某种方式查询或修改此内部状态的方法。 Smalltalk 和 Java 是面向对象的语言。 C++ 和 Python 是支持面向对象编程的语言,但不强制使用面向对象的特性。
  • 函数式 编程将问题分解为一组函数。 理想情况下,函数只接受输入并产生输出,并且没有任何影响给定输入产生的输出的内部状态。 著名的函数式语言包括 ML 系列(标准 ML、OCaml 和其他变体)和 Haskell。

某些计算机语言的设计者选择强调一种特定的编程方法。 这通常会使编写使用不同方法的程序变得困难。 其他语言是支持多种不同方法的多范式语言。 Lisp、C++ 和 Python 是多范式的; 您可以使用所有这些语言编写主要是过程性、面向对象或功能性的程序或库。 在一个大型程序中,可能会使用不同的方法编写不同的部分; 例如,GUI 可能是面向对象的,而处理逻辑是程序性的或功能性的。

在函数式程序中,输入流经一组函数。 每个函数对其输入进行操作并产生一些输出。 函数式风格不鼓励具有副作用的函数,这些函数会修改内部状态或进行在函数返回值中不可见的其他更改。 完全没有副作用的函数称为纯函数。 避免副作用意味着不使用随着程序运行而更新的数据结构; 每个函数的输出必须只依赖于它的输入。

有些语言对纯度非常严格,甚至没有赋值语句,例如 a=3c = a + b,但很难避免所有副作用,例如打印到屏幕或写入磁盘文件。 另一个例子是调用 print()time.sleep() 函数,这两个函数都没有返回有用的值。 两者都只是因为它们向屏幕发送一些文本或暂停执行一秒钟的副作用而被调用。

以函数式风格编写的 Python 程序通常不会走到避免所有 I/O 或所有分配的极端; 相反,他们将提供一个功能性的界面,但会在内部使用非功能性的特性。 例如,函数的实现仍然会使用对局部变量的赋值,但不会修改全局变量或产生其他副作用。

函数式编程可以被认为是面向对象编程的对立面。 对象是包含一些内部状态以及允许您修改此状态的一组方法调用的小胶囊,程序由进行正确的状态更改集组成。 函数式编程希望尽可能避免状态更改,并处理函数之间的数据流动。 在 Python 中,您可以通过编写接受和返回表示应用程序中的对象(电子邮件消息、事务等)的实例的函数来组合这两种方法。

功能设计似乎是一个奇怪的工作限制。 为什么要避免对象和副作用? 函数式风格具有理论和实践优势:

  • 正式的可证明性。
  • 模块化。
  • 可组合性。
  • 易于调试和测试。

形式证明

理论上的好处是更容易构建函数式程序正确的数学证明。

长期以来,研究人员一直对寻找数学证明程序正确的方法感兴趣。 这不同于在大量输入上测试程序并得出其输出通常是正确的结论,或阅读程序的源代码并得出代码看起来正确的结论; 相反,目标是严格证明程序为所有可能的输入产生正确的结果。

用于证明程序正确的技术是写下 不变量 、输入数据和程序变量的属性,这些属性始终为真。 对于每一行代码,你然后证明如果不变量 X 和 Y 为真 before 行被执行,略有不同的不变量 X' 和 Y' 为真 after 行是执行。 这一直持续到程序结束,此时不变量应该与程序输出的所需条件相匹配。

函数式编程避免赋值的出现是因为这种技术很难处理赋值; 赋值可以破坏赋值之前为真的不变量,而不会产生任何可以向前传播的新不变量。

不幸的是,证明程序正确在很大程度上是不切实际的,并且与 Python 软件无关。 即使是微不足道的程序也需要几页长的证明; 中等复杂程序的正确性证明将是巨大的,并且您每天使用的程序(Python 解释器、您的 XML 解析器、您的 Web 浏览器)很少或没有一个可以被证明是正确的。 即使你写下或生成了一个证明,那么也会有验证这个证明的问题; 也许其中存在错误,并且您错误地认为您已经证明了该程序是正确的。


模块化

函数式编程的一个更实际的好处是它迫使您将问题分解成小块。 因此,程序更加模块化。 指定和编写一个只做一件事的小函数比一个执行复杂转换的大函数更容易。 小函数也更易于阅读和检查错误。


易于调试和测试

测试和调试函数式程序更容易。

调试被简化,因为功能通常很小且明确指定。 当程序不工作时,每个函数都是一个接口点,您可以在其中检查数据是否正确。 您可以查看中间输入和输出以快速隔离导致错误的函数。

测试更容易,因为每个功能都是单元测试的潜在主题。 函数不依赖于在运行测试之前需要复制的系统状态; 相反,您只需合成正确的输入,然后检查输出是否符合预期。


可组合性

在处理函数式程序时,您将编写许多具有不同输入和输出的函数。 其中一些功能不可避免地专门用于特定应用程序,但其他功能将在各种程序中有用。 例如,采用目录路径并返回目录中所有 XML 文件的函数,或者采用文件名并返回其内容的函数,可以应用于许多不同的情况。

随着时间的推移,您将形成一个个人实用程序库。 通常,您会通过在新配置中安排现有函数并编写一些专门用于当前任务的函数来组装新程序。


迭代器

我将首先研究 Python 语言特性,它是编写函数式程序的重要基础:迭代器。

迭代器是表示数据流的对象; 此对象一次返回一个元素的数据。 Python 迭代器必须支持名为 __next__() 的方法,该方法不接受任何参数并始终返回流的下一个元素。 如果流中没有更多元素,则 __next__() 必须引发 StopIteration 异常。 不过,迭代器不一定是有限的; 编写一个产生无限数据流的迭代器是完全合理的。

内置的 iter() 函数接受一个任意对象并尝试返回一个迭代器,该迭代器将返回该对象的内容或元素,如果该对象不支持迭代,则会引发 TypeError。 Python 的一些内置数据类型支持迭代,最常见的是列表和字典。 如果您可以获得一个迭代器,则该对象称为 iterable

您可以手动试验迭代界面:

>>> L = [1, 2, 3]
>>> it = iter(L)
>>> it  
<...iterator object at ...>
>>> it.__next__()  # same as next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

Python 期望在几个不同的上下文中可迭代对象,最重要的是 for 语句。 在语句 for X in Y 中,Y 必须是迭代器或 iter() 可以为其创建迭代器的某个对象。 这两个语句是等价的:

for i in iter(obj):
    print(i)

for i in obj:
    print(i)

通过使用 list()tuple() 构造函数,可以将迭代器具体化为列表或元组:

>>> L = [1, 2, 3]
>>> iterator = iter(L)
>>> t = tuple(iterator)
>>> t
(1, 2, 3)

序列解包也支持迭代器:如果你知道一个迭代器会返回 N 个元素,你可以将它们解包成一个 N 元组:

>>> L = [1, 2, 3]
>>> iterator = iter(L)
>>> a, b, c = iterator
>>> a, b, c
(1, 2, 3)

max()min() 等内置函数可以采用单个迭代器参数,并返回最大或最小元素。 "in""not in" 运算符也支持迭代器:如果在迭代器返回的流中找到 X,则 X in iterator 为真。 如果迭代器是无限的,你会遇到明显的问题; max(), min() 永远不会返回,如果元素 X 永远不会出现在流中,则 "in""not in" 算子赢了也不回。

请注意,您只能在迭代器中前进; 无法获取前一个元素、重置迭代器或复制它。 迭代器对象可以选择提供这些附加功能,但迭代器协议仅指定 __next__() 方法。 因此,函数可能会消耗迭代器的所有输出,如果您需要对同一流执行不同的操作,则必须创建一个新的迭代器。

支持迭代器的数据类型

我们已经看到列表和元组如何支持迭代器。 事实上,任何 Python 序列类型,例如字符串,都会自动支持创建迭代器。

在字典上调用 iter() 会返回一个迭代器,该迭代器将遍历字典的键:

>>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
...      'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
>>> for key in m:
...     print(key, m[key])
Jan 1
Feb 2
Mar 3
Apr 4
May 5
Jun 6
Jul 7
Aug 8
Sep 9
Oct 10
Nov 11
Dec 12

请注意,从 Python 3.7 开始,字典迭代顺序保证与插入顺序相同。 在早期版本中,行为未指定并且可能因实现而异。

iter() 应用于字典总是遍历键,但字典具有返回其他迭代器的方法。 如果要迭代值或键/值对,可以显式调用 values()items() 方法来获得合适的迭代器。

dict() 构造函数可以接受一个迭代器,它返回一个有限的 (key, value) 元组流:

>>> L = [('Italy', 'Rome'), ('France', 'Paris'), ('US', 'Washington DC')]
>>> dict(iter(L))
{'Italy': 'Rome', 'France': 'Paris', 'US': 'Washington DC'}

文件还通过调用 readline() 方法来支持迭代,直到文件中没有更多行。 这意味着您可以像这样读取文件的每一行:

for line in file:
    # do something for each line
    ...

集合可以从可迭代对象中获取它们的内容,并让您迭代集合的元素:

S = {2, 3, 5, 7, 11, 13}
for i in S:
    print(i)

生成器表达式和列表推导式

迭代器输出的两个常见操作是 1) 对每个元素执行一些操作,2) 选择满足某些条件的元素子集。 例如,给定一个字符串列表,您可能希望从每一行中去除尾随空格或提取包含给定子字符串的所有字符串。

列表推导式和生成器表达式(简称:“listcomps”和“genexps”)是此类操作的简明符号,借用自函数式编程语言 Haskell (https://www.haskell.org/) . 您可以使用以下代码从字符串流中去除所有空格:

line_list = ['  line 1\n', 'line 2  \n', ...]

# Generator expression -- returns iterator
stripped_iter = (line.strip() for line in line_list)

# List comprehension -- returns list
stripped_list = [line.strip() for line in line_list]

您可以通过添加 "if" 条件来仅选择某些元素:

stripped_list = [line.strip() for line in line_list
                 if line != ""]

通过列表理解,你会得到一个 Python 列表; stripped_list 是包含结果行的列表,而不是迭代器。 生成器表达式返回一个迭代器,它根据需要计算值,不需要一次实现所有值。 这意味着如果您正在使用返回无限流或大量数据的迭代器,则列表推导式没有用。 在这些情况下,生成器表达式更可取。

生成器表达式用括号(“()”)括起来,列表推导式用方括号(“[]”)括起来。 生成器表达式具有以下形式:

( expression for expr in sequence1
             if condition1
             for expr2 in sequence2
             if condition2
             for expr3 in sequence3 ...
             if condition3
             for exprN in sequenceN
             if conditionN )

同样,对于列表理解,只有外括号不同(方括号而不是圆括号)。

生成的输出的元素将是 expression 的连续值。 if 子句都是可选的; 如果存在,仅当 condition 为真时才会评估 expression 并将其添加到结果中。

生成器表达式总是必须写在括号内,但发出函数调用信号的括号也算在内。 如果您想创建一个将立即传递给函数的迭代器,您可以编写:

obj_total = sum(obj.count for obj in list_all_objects())

for...in 子句包含要迭代的序列。 序列的长度不必相同,因为它们是从左到右迭代的, 不是 并行。 对于 sequence1 中的每个元素,sequence2 从头开始循环。 sequence3 然后为来自 sequence1sequence2 的每个结果元素对循环。

换句话说,列表推导式或生成器表达式等效于以下 Python 代码:

for expr1 in sequence1:
    if not (condition1):
        continue   # Skip this element
    for expr2 in sequence2:
        if not (condition2):
            continue   # Skip this element
        ...
        for exprN in sequenceN:
            if not (conditionN):
                continue   # Skip this element

            # Output the value of
            # the expression.

这意味着当有多个 for...in 子句但没有 if 子句时,结果输出的长度将等于所有序列长度的乘积。 如果您有两个长度为 3 的列表,则输出列表的长度为 9 个元素:

>>> seq1 = 'abc'
>>> seq2 = (1, 2, 3)
>>> [(x, y) for x in seq1 for y in seq2]  
[('a', 1), ('a', 2), ('a', 3),
 ('b', 1), ('b', 2), ('b', 3),
 ('c', 1), ('c', 2), ('c', 3)]

为了避免在 Python 的语法中引入歧义,如果 expression 正在创建一个元组,它必须用括号括起来。 下面的第一个列表理解是一个语法错误,而第二个是正确的:

# Syntax error
[x, y for x in seq1 for y in seq2]
# Correct
[(x, y) for x in seq1 for y in seq2]

发电机

生成器是一类特殊的函数,可以简化编写迭代器的任务。 常规函数计算一个值并返回它,但生成器返回一个迭代器,它返回一个值流。

您无疑熟悉 Python 或 C 中常规函数调用的工作方式。 当您调用一个函数时,它会获得一个私有命名空间,在该命名空间中创建了它的局部变量。 当函数到达return语句时,局部变量被销毁,并将值返回给调用者。 稍后对同一函数的调用会创建一个新的私有命名空间和一组新的局部变量。 但是,如果在退出函数时没有丢弃局部变量呢? 如果您稍后可以恢复它停止的功能怎么办? 这就是生成器提供的; 它们可以被认为是可恢复的功能。

这是生成器函数的最简单示例:

>>> def generate_ints(N):
...    for i in range(N):
...        yield i

任何包含 yield 关键字的函数都是生成器函数; 这是由 Python 的 bytecode 编译器检测到的,该编译器因此专门编译该函数。

当您调用生成器函数时,它不会返回单个值; 相反,它返回一个支持迭代器协议的生成器对象。 在执行 yield 表达式时,生成器输出 i 的值,类似于 return 语句。 yieldreturn 语句之间的最大区别在于,在到达 yield 时,生成器的执行状态被挂起并保留局部变量。 在下次调用生成器的 __next__() 方法时,该函数将继续执行。

以下是 generate_ints() 生成器的示例用法:

>>> gen = generate_ints(3)
>>> gen  
<generator object generate_ints at ...>
>>> next(gen)
0
>>> next(gen)
1
>>> next(gen)
2
>>> next(gen)
Traceback (most recent call last):
  File "stdin", line 1, in <module>
  File "stdin", line 2, in generate_ints
StopIteration

你同样可以写 for i in generate_ints(5)a, b, c = generate_ints(3)

在一个生成器函数中,return value 导致 StopIteration(value)__next__() 方法被引发。 一旦发生这种情况,或者到达函数的底部,值的处理结束并且生成器不能产生任何进一步的值。

您可以通过编写自己的类并将生成器的所有局部变量存储为实例变量来手动实现生成器的效果。 例如,可以通过将 self.count 设置为 0 并让 __next__() 方法递增 self.count 并返回它来返回整数列表。 然而,对于一个中等复杂的生成器,编写相应的类可能会更加混乱。

Python 库中包含的测试套件 :source:`Lib/test/test_generators.py` 包含许多更有趣的示例。 这是一个使用生成器递归实现树的有序遍历的生成器。

# A recursive generator that generates Tree leaves in in-order.
def inorder(t):
    if t:
        for x in inorder(t.left):
            yield x

        yield t.label

        for x in inorder(t.right):
            yield x

test_generators.py 中的另外两个示例为 N-Queens 问题(将 N 个皇后放在 NxN 棋盘上,以便没有皇后威胁另一个皇后)和骑士之旅(找到一条将骑士带到每个方格的路线)的解决方案一个 NxN 棋盘,无需两次访问任何方块)。

将值传递给生成器

在 Python 2.4 及更早版本中,生成器只产生输出。 一旦调用生成器的代码来创建迭代器,在恢复执行时就无法将任何新信息传递给函数。 您可以通过让生成器查看全局变量或通过传入一些调用者然后修改的可变对象来组合这种能力,但这些方法是混乱的。

在 Python 2.5 中,有一种简单的方法可以将值传递给生成器。 yield 变成了一个表达式,返回一个可以赋值给变量或以其他方式操作的值:

val = (yield i)

我建议您 始终 在使用返回值执行某些操作时在 yield 表达式周围放置括号,如上例所示。 括号并不总是必要的,但总是添加它们更容易,而不必记住何时需要它们。

PEP 342 解释了确切的规则,即 yield 表达式必须始终用括号括起来,除非它出现在右侧的顶级表达式中-作业的手边。 这意味着您可以编写 val = yield i,但在进行操作时必须使用括号,如 val = (yield i) + 12。)

通过调用其 send(value) 方法将值发送到生成器。 此方法恢复生成器的代码并且 yield 表达式返回指定的值。 如果调用常规的 __next__() 方法,则 yield 返回 None

这是一个简单的计数器,递增 1 并允许更改内部计数器的值。

def counter(maximum):
    i = 0
    while i < maximum:
        val = (yield i)
        # If value provided, change counter
        if val is not None:
            i = val
        else:
            i += 1

这是更改计数器的示例:

>>> it = counter(10)  
>>> next(it)  
0
>>> next(it)  
1
>>> it.send(8)  
8
>>> next(it)  
9
>>> next(it)  
Traceback (most recent call last):
  File "t.py", line 15, in <module>
    it.next()
StopIteration

因为 yield 经常会返回 None,所以你应该经常检查这种情况。 不要只在表达式中使用它的值,除非您确定 send() 方法将是用于恢复生成器函数的唯一方法。

除了 send() 之外,生成器还有另外两种方法:

这些变化的累积效应是将生成者从信息的单向生产者转变为生产者和消费者。

生成器也变成了 协程 ,一种更通用的子程序形式。 子程序在一个点进入并在另一个点退出(函数的顶部,和一个 return 语句),但是协程可以在许多不同的点进入、退出和恢复(yield ] 语句)。


内置功能

让我们更详细地了解经常与迭代器一起使用的内置函数。

Python 的两个内置函数 map()filter() 复制了生成器表达式的特征:

map(f, iterA, iterB, ...) 返回序列上的迭代器

f(iterA[0], iterB[0]), f(iterA[1], iterB[1]), f(iterA[2], iterB[2]), ...

>>> def upper(s):
...     return s.upper()
>>> list(map(upper, ['sentence', 'fragment']))
['SENTENCE', 'FRAGMENT']
>>> [upper(s) for s in ['sentence', 'fragment']]
['SENTENCE', 'FRAGMENT']

您当然可以使用列表理解来达到相同的效果。

filter(predicate, iter) 返回一个遍历所有满足特定条件的序列元素的迭代器,同样被列表推导式复制。 predicate 是一个返回某个条件真值的函数; 要与 filter() 一起使用,谓词必须采用单个值。

>>> def is_even(x):
...     return (x % 2) == 0
>>> list(filter(is_even, range(10)))
[0, 2, 4, 6, 8]

这也可以写成列表理解:

>>> list(x for x in range(10) if is_even(x))
[0, 2, 4, 6, 8]

enumerate(iter, start=0) 对迭代中的元素进行计数,返回包含计数(来自 start)和每个元素的 2 元组。

>>> for item in enumerate(['subject', 'verb', 'object']):
...     print(item)
(0, 'subject')
(1, 'verb')
(2, 'object')

enumerate() 在循环遍历列表并记录满足特定条件的索引时经常使用:

f = open('data.txt', 'r')
for i, line in enumerate(f):
    if line.strip() == '':
        print('Blank line at line #%i' % i)

sorted(iterable, key=None, reverse=False) 将iterable的所有元素收集到一个列表中,对列表进行排序,返回排序后的结果。 keyreverse 参数被传递到构造列表的 sort() 方法。

>>> import random
>>> # Generate 8 random numbers between [0, 10000)
>>> rand_list = random.sample(range(10000), 8)
>>> rand_list  
[769, 7953, 9828, 6431, 8442, 9878, 6213, 2207]
>>> sorted(rand_list)  
[769, 2207, 6213, 6431, 7953, 8442, 9828, 9878]
>>> sorted(rand_list, reverse=True)  
[9878, 9828, 8442, 7953, 6431, 6213, 2207, 769]

(有关排序的更详细讨论,请参阅 Sorting HOW TO。)

any(iter)all(iter) 内置函数查看可迭代内容的真值。 any() 如果迭代中的任何元素为真值,则返回 True,如果所有元素都为真值,则 all() 返回 True真实值:

>>> any([0, 1, 0])
True
>>> any([0, 0, 0])
False
>>> any([1, 1, 1])
True
>>> all([0, 1, 0])
False
>>> all([0, 0, 0])
False
>>> all([1, 1, 1])
True

zip(iterA, iterB, ...) 从每个可迭代对象中取出一个元素并在元组中返回它们:

zip(['a', 'b', 'c'], (1, 2, 3)) =>
  ('a', 1), ('b', 2), ('c', 3)

它不会构造内存列表并在返回之前耗尽所有输入迭代器; 相反,元组仅在被请求时才被构造和返回。 (这种行为的技术术语是 懒惰评估 。)

此迭代器旨在与长度相同的可迭代对象一起使用。 如果可迭代对象的长度不同,则生成的流将与最短的可迭代对象长度相同。

zip(['a', 'b'], (1, 2, 3)) =>
  ('a', 1), ('b', 2)

但是,您应该避免这样做,因为元素可能会从较长的迭代器中取出并被丢弃。 这意味着您不能继续使用迭代器,因为您可能会跳过丢弃的元素。


itertools 模块

itertools 模块包含许多常用的迭代器以及用于组合多个迭代器的函数。 本节将通过展示小例子来介绍模块的内容。

该模块的功能分为几个大类:

  • 基于现有迭代器创建新迭代器的函数。
  • 将迭代器的元素视为函数参数的函数。
  • 用于选择迭代器输出部分的函数。
  • 用于对迭代器的输出进行分组的函数。

创建新的迭代器

itertools.count(start, step) 返回均匀间隔值的无限流。 您可以选择提供起始编号(默认为 0)和数字之间的间隔(默认为 1):

itertools.count() =>
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
itertools.count(10) =>
  10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...
itertools.count(10, 5) =>
  10, 15, 20, 25, 30, 35, 40, 45, 50, 55, ...

itertools.cycle(iter) 保存提供的可迭代内容的副本并返回一个新的迭代器,该迭代器从头到尾返回其元素。 新的迭代器将无限重复这些元素。

itertools.cycle([1, 2, 3, 4, 5]) =>
  1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...

itertools.repeat(elem, [n]) 返回提供的元素 n 次,或者如果没有提供 n 则无限返回元素。

itertools.repeat('abc') =>
  abc, abc, abc, abc, abc, abc, abc, abc, abc, abc, ...
itertools.repeat('abc', 5) =>
  abc, abc, abc, abc, abc

itertools.chain(iterA, iterB, ...) 将任意数量的迭代器作为输入,并返回第一个迭代器的所有元素,然后是第二个迭代器的所有元素,依此类推,直到所有可迭代对象都已用尽。

itertools.chain(['a', 'b', 'c'], (1, 2, 3)) =>
  a, b, c, 1, 2, 3

itertools.islice(iter, [start], stop, [step]) 返回一个流,它是迭代器的一个切片。 使用单个 stop 参数,它将返回第一个 stop 元素。 如果您提供起始索引,您将获得 stop-start 元素,如果您为 step 提供值,则将相应地跳过元素。 与 Python 的字符串和列表切片不同,您不能对 startstopstep 使用负值。

itertools.islice(range(10), 8) =>
  0, 1, 2, 3, 4, 5, 6, 7
itertools.islice(range(10), 2, 8) =>
  2, 3, 4, 5, 6, 7
itertools.islice(range(10), 2, 8, 2) =>
  2, 4, 6

itertools.tee(iter, [n]) 复制一个迭代器; 它返回 n 个独立迭代器,这些迭代器都将返回源迭代器的内容。 如果您不为 n 提供值,则默认值为 2。 复制迭代器需要保存源迭代器的一些内容,因此如果迭代器很大并且新迭代器之一比其他迭代器消耗更多,这会消耗大量内存。

itertools.tee( itertools.count() ) =>
   iterA, iterB

where iterA ->
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...

and   iterB ->
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...

在元素上调用函数

operator 模块包含一组对应于 Python 运算符的函数。 一些示例是 operator.add(a, b)(添加两个值)、operator.ne(a, b)(与 a != b 相同)和 [ X117X]operator.attrgetter('id')(返回一个获取 .id 属性的可调用对象)。

itertools.starmap(func, iter) 假设可迭代对象将返回一个元组流,并使用这些元组作为参数调用 func

itertools.starmap(os.path.join,
                  [('/bin', 'python'), ('/usr', 'bin', 'java'),
                   ('/usr', 'bin', 'perl'), ('/usr', 'bin', 'ruby')])
=>
  /bin/python, /usr/bin/java, /usr/bin/perl, /usr/bin/ruby

选择元素

另一组函数根据谓词选择迭代器元素的子集。

itertools.filterfalse(predicate, iter)filter() 相反,返回谓词返回 false 的所有元素:

itertools.filterfalse(is_even, itertools.count()) =>
  1, 3, 5, 7, 9, 11, 13, 15, ...

itertools.takewhile(predicate, iter) 返回元素,只要谓词返回 true。 一旦谓词返回 false,迭代器将发出结果结束的信号。

def less_than_10(x):
    return x < 10

itertools.takewhile(less_than_10, itertools.count()) =>
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9

itertools.takewhile(is_even, itertools.count()) =>
  0

itertools.dropwhile(predicate, iter) 在谓词返回真时丢弃元素,然后返回可迭代结果的其余部分。

itertools.dropwhile(less_than_10, itertools.count()) =>
  10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...

itertools.dropwhile(is_even, itertools.count()) =>
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...

itertools.compress(data, selectors) 接受两个迭代器并只返回 dataselectors 的对应元素为真的那些元素,只要有一个就停止筋疲力尽:

itertools.compress([1, 2, 3, 4, 5], [True, True, False, False, True]) =>
   1, 2, 5

组合函数

itertools.combinations(iterable, r) 返回一个迭代器,给出 iterable 中包含的元素的所有可能的 r 元组组合。

itertools.combinations([1, 2, 3, 4, 5], 2) =>
  (1, 2), (1, 3), (1, 4), (1, 5),
  (2, 3), (2, 4), (2, 5),
  (3, 4), (3, 5),
  (4, 5)

itertools.combinations([1, 2, 3, 4, 5], 3) =>
  (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5),
  (2, 3, 4), (2, 3, 5), (2, 4, 5),
  (3, 4, 5)

每个元组中的元素保持与 iterable 返回它们相同的顺序。 例如,在上述示例中,数字 1 始终位于 2、3、4 或 5 之前。 一个类似的函数,itertools.permutations(iterable, r=None),移除了这个对顺序的限制,返回所有可能的长度为 r 的排列:

itertools.permutations([1, 2, 3, 4, 5], 2) =>
  (1, 2), (1, 3), (1, 4), (1, 5),
  (2, 1), (2, 3), (2, 4), (2, 5),
  (3, 1), (3, 2), (3, 4), (3, 5),
  (4, 1), (4, 2), (4, 3), (4, 5),
  (5, 1), (5, 2), (5, 3), (5, 4)

itertools.permutations([1, 2, 3, 4, 5]) =>
  (1, 2, 3, 4, 5), (1, 2, 3, 5, 4), (1, 2, 4, 3, 5),
  ...
  (5, 4, 3, 2, 1)

如果您不为 r 提供值,则使用可迭代的长度,这意味着所有元素都被置换。

请注意,这些函数按位置生成所有可能的组合,并且不需要 iterable 的内容是唯一的:

itertools.permutations('aba', 3) =>
  ('a', 'b', 'a'), ('a', 'a', 'b'), ('b', 'a', 'a'),
  ('b', 'a', 'a'), ('a', 'a', 'b'), ('a', 'b', 'a')

相同的元组 ('a', 'a', 'b') 出现了两次,但两个 'a' 字符串来自不同的位置。

itertools.combinations_with_replacement(iterable, r) 函数放宽了不同的约束:元素可以在单个元组中重复。 从概念上讲,为每个元组的第一个位置选择一个元素,然后在选择第二个元素之前替换它。

itertools.combinations_with_replacement([1, 2, 3, 4, 5], 2) =>
  (1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
  (2, 2), (2, 3), (2, 4), (2, 5),
  (3, 3), (3, 4), (3, 5),
  (4, 4), (4, 5),
  (5, 5)

分组元素

我将讨论的最后一个函数 itertools.groupby(iter, key_func=None) 是最复杂的。 key_func(elem) 是一个函数,可以为迭代返回的每个元素计算一个键值。 如果您不提供键函数,键就是每个元素本身。

groupby() 从底层迭代中收集所有具有相同键值的连续元素,并返回一个包含键值和具有该键的元素的迭代器的 2 元组流。

city_list = [('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL'),
             ('Anchorage', 'AK'), ('Nome', 'AK'),
             ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ'),
             ...
            ]

def get_state(city_state):
    return city_state[1]

itertools.groupby(city_list, get_state) =>
  ('AL', iterator-1),
  ('AK', iterator-2),
  ('AZ', iterator-3), ...

where
iterator-1 =>
  ('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL')
iterator-2 =>
  ('Anchorage', 'AK'), ('Nome', 'AK')
iterator-3 =>
  ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ')

groupby() 假设底层迭代的内容已经根据键进行了排序。 请注意,返回的迭代器也使用底层迭代器,因此您必须在请求 iterator-2 及其对应的 key 之前使用 iterator-1 的结果。


功能工具模块

Python 2.5 中的 functools 模块包含一些高阶函数。 高阶函数 将一个或多个函数作为输入并返回一个新函数。 该模块中最有用的工具是 functools.partial() 函数。

对于以函数式风格编写的程序,您有时会希望构建填充了一些参数的现有函数的变体。 考虑一个 Python 函数 f(a, b, c); 你可能希望创建一个新的函数 g(b, c) 相当于 f(1, b, c); 您正在为 f() 的参数之一填充值。 这称为“部分功能应用”。

partial() 的构造函数采用参数 (function, arg1, arg2, ..., kwarg1=value1, kwarg2=value2)。 结果对象是可调用的,因此您可以调用它来使用填充的参数调用 function

这是一个小而现实的例子:

import functools

def log(message, subsystem):
    """Write the contents of 'message' to the specified subsystem."""
    print('%s: %s' % (subsystem, message))
    ...

server_log = functools.partial(log, subsystem='server')
server_log('Unable to open socket')

functools.reduce(func, iter, [initial_value]) 累积对所有可迭代元素执行操作,因此不能应用于无限可迭代元素。 func 必须是一个接受两个元素并返回一个值的函数。 functools.reduce() 取迭代器返回的前两个元素 A 和 B 并计算 func(A, B)。 然后它请求第三个元素 C,计算 func(func(A, B), C),将此结果与返回的第四个元素组合,并继续直到迭代用完。 如果可迭代对象根本没有返回值,则会引发 TypeError 异常。 如果提供了初始值,则将其用作起点,并且 func(initial_value, A) 是第一个计算。

>>> import operator, functools
>>> functools.reduce(operator.concat, ['A', 'BB', 'C'])
'ABBC'
>>> functools.reduce(operator.concat, [])
Traceback (most recent call last):
  ...
TypeError: reduce() of empty sequence with no initial value
>>> functools.reduce(operator.mul, [1, 2, 3], 1)
6
>>> functools.reduce(operator.mul, [], 1)
1

如果您将 operator.add()functools.reduce() 一起使用,您将把可迭代对象的所有元素相加。 这种情况非常常见,以至于有一个特殊的内置函数 sum() 来计算它:

>>> import functools, operator
>>> functools.reduce(operator.add, [1, 2, 3, 4], 0)
10
>>> sum([1, 2, 3, 4])
10
>>> sum([])
0

但是,对于 functools.reduce() 的许多用途,只需编写明显的 for 循环会更清晰:

import functools
# Instead of:
product = functools.reduce(operator.mul, [1, 2, 3], 1)

# You can write:
product = 1
for i in [1, 2, 3]:
    product *= i

一个相关的函数是 itertools.accumulate(iterable, func=operator.add)。 它执行相同的计算,但不是只返回最终结果,accumulate() 返回一个迭代器,该迭代器也产生每个部分结果:

itertools.accumulate([1, 2, 3, 4, 5]) =>
  1, 3, 6, 10, 15

itertools.accumulate([1, 2, 3, 4, 5], operator.mul) =>
  1, 2, 6, 24, 120

操作员模块

operator 模块前面已经提到过。 它包含一组对应于 Python 操作符的函数。 这些函数在函数式代码中通常很有用,因为它们使您无需编写执行单个操作的琐碎函数。

该模块中的一些功能是:

  • 数学运算:add()sub()mul()floordiv()abs()、……
  • 逻辑运算:not_()truth()
  • 按位运算:and_()or_()invert()
  • 比较:eq()ne()lt()le()gt()ge()
  • 对象标识:is_()is_not()

有关完整列表,请参阅操作员模块的文档。


小函数和 lambda 表达式

在编写函数式程序时,您通常需要一些充当谓词或以某种方式组合元素的函数。

如果有合适的 Python 内置函数或模块函数,则根本不需要定义新函数:

stripped_lines = [line.strip() for line in lines]
existing_files = filter(os.path.exists, file_list)

如果您需要的函数不存在,则需要编写它。 编写小函数的一种方法是使用 lambda 表达式。 lambda 接受多个参数和组合这些参数的表达式,并创建一个返回表达式值的匿名函数:

adder = lambda x, y: x+y

print_assign = lambda name, value: name + '=' + str(value)

另一种方法是使用 def 语句并以通常的方式定义函数:

def adder(x, y):
    return x + y

def print_assign(name, value):
    return name + '=' + str(value)

哪个替代方案更可取? 这是一个风格问题; 我通常的做法是避免使用 lambda

我偏爱的原因之一是 lambda 在它可以定义的功能方面非常有限。 结果必须可以作为单个表达式进行计算,这意味着您不能进行多路 if... elif... else 比较或 try... except 语句。 如果您试图在 lambda 语句中做太多事情,最终会得到一个难以阅读的过于复杂的表达式。 快,下面的代码在做什么?

import functools
total = functools.reduce(lambda a, b: (0, a[1] + b[1]), items)[1]

您可以弄清楚,但需要时间来理清表达式以弄清楚发生了什么。 使用简短的嵌套 def 语句会使事情变得更好:

import functools
def combine(a, b):
    return 0, a[1] + b[1]

total = functools.reduce(combine, items)[1]

但如果我只是使用 for 循环,那将是最好的:

total = 0
for a, b in items:
    total += b

或者 sum() 内置和生成器表达式:

total = sum(b for a, b in items)

functools.reduce() 的许多用途在编写为 for 循环时更加清晰。

Fredrik Lundh 曾经建议使用以下规则来重构 lambda 的使用:

  1. 编写一个 lambda 函数。
  2. 写一条评论来解释 lambda 的作用。
  3. 研究一下评论,然后想出一个能抓住评论本质的名字。
  4. 使用该名称将 lambda 转换为 def 语句。
  5. 删除评论。

我真的很喜欢这些规则,但你可以自由地不同意这种无 lambda 的风格是否更好。


修订历史和致谢

作者要感谢以下人员对本文的各种草稿提供建议、更正和帮助:Ian Bicking、Nick Coghlan、Nick Efford、Raymond Hettinger、Jim Jewett、Mike Krell、Leandro Lameiro、Jussi Salmela、Collin Winter,布莱克温顿。

0.1 版:2006 年 6 月 30 日发布。

0.11 版:2006 年 7 月 1 日发布。 错别字修复。

0.2 版:2006 年 7 月 10 日发布。 将 genexp 和 listcomp 部分合并为一个。 错别字修复。

0.21 版:在导师邮件列表中添加了更多建议参考。

0.30 版本:在 Collin Winter 编写的 functional 模块上添加了一个部分; 在操作员模块上添加了简短的部分; 其他一些编辑。


参考

一般

计算机程序的结构和解释 ,Harold Abelson 和 Gerald Jay Sussman 与 Julie Sussman 合着。 全文在 https://mitpress.mit.edu/sicp/。 在这本经典的计算机科学教科书中,第 2 章和第 3 章讨论了使用序列和流来组织程序内的数据流。 本书使用 Scheme 作为示例,但这些章节中描述的许多设计方法都适用于函数式 Python 代码。

http://www.defmacro.org/ramblings/fp.html:函数式编程的一般介绍,使用 Java 示例,并有冗长的历史介绍。

https://en.wikipedia.org/wiki/Functional_programming:描述函数式编程的一般维基百科条目。

https://en.wikipedia.org/wiki/Coroutine:协程入口。

https://en.wikipedia.org/wiki/Currying:柯里化概念的入口。


特定于 Python 的

http://gnosis.cx/TPiP/:David Mertz 的书 Text Processing in Python 的第一章讨论了文本处理的函数式编程,在标题为“利用高阶文本处理中的函数”。

Mertz 还为 IBM 的 DeveloperWorks 站点撰写了关于函数式编程的 3 部分系列文章; 见第1部分第2部分第3部分


Python 文档

itertools 模块的文档。

functools 模块的文档。

operator 模块的文档。

PEP 289:“生成器表达式”

PEP 342:“Coroutines via Enhanced Generators”描述了 Python 2.5 中的新生成器特性。