Skip to content

Commit eecc635

Browse files
committed
This is not a how-to guide; the title has been changed. A future commit should move the document out of /howto This patch removes comments about what the author thinks the reader is familiar with, and the first-person voice that sometimes appeared. Some wording that dated the document has been changed.
1 parent 5aa6964 commit eecc635

File tree

1 file changed

+24
-51
lines changed

1 file changed

+24
-51
lines changed

Doc/howto/functional.rst

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,24 @@
11
********************************
2-
Functional Programming HOWTO
2+
Functional programming in Python
33
********************************
44

55
:Author: A. M. Kuchling
66
:Release: 0.32
77

8-
In this document, we'll take a tour of Python's features suitable for
9-
implementing programs in a functional style. After an introduction to the
10-
concepts of functional programming, we'll look at language features such as
11-
:term:`iterator`\s and :term:`generator`\s and relevant library modules such as
12-
:mod:`itertools` and :mod:`functools`.
138

14-
15-
Introduction
16-
============
17-
18-
This section explains the basic concept of functional programming; if
19-
you're just interested in learning about Python language features,
20-
skip to the next section on :ref:`functional-howto-iterators`.
9+
The basics of functional programming
10+
====================================
2111

2212
Programming languages support decomposing problems in several different ways:
2313

24-
* Most programming languages are **procedural**: programs are lists of
14+
* Many programming languages are **procedural**: programs are lists of
2515
instructions that tell the computer what to do with the program's input. C,
2616
Pascal, and even Unix shells are procedural languages.
2717

2818
* In **declarative** languages, you write a specification that describes the
2919
problem to be solved, and the language implementation figures out how to
30-
perform the computation efficiently. SQL is the declarative language you're
31-
most likely to be familiar with; a SQL query describes the data set you want
20+
perform the computation efficiently. SQL is an example of a declarative
21+
language; a SQL query describes the data set you want
3222
to retrieve, and the SQL engine decides whether to scan tables or use indexes,
3323
which subclauses should be performed first, etc.
3424

@@ -57,7 +47,7 @@ functional, for example.
5747

5848
In a functional program, input flows through a set of functions. Each function
5949
operates on its input and produces some output. Functional style discourages
60-
functions with side effects that modify internal state or make other changes
50+
functions with *side effects* that modify internal state or make other changes
6151
that aren't visible in the function's return value. Functions that have no side
6252
effects at all are called **purely functional**. Avoiding side effects means
6353
not using data structures that get updated as a program runs; every function's
@@ -177,7 +167,7 @@ a few functions specialized for the current task.
177167
Iterators
178168
=========
179169

180-
I'll start by looking at a Python language feature that's an important
170+
Let's start by considering a Python language feature that's an important
181171
foundation for writing functional-style programs: iterators.
182172

183173
An iterator is an object representing a stream of data; this object returns the
@@ -259,7 +249,6 @@ consume all of the iterator's output, and if you need to do something different
259249
with the same stream, you'll have to create a new iterator.
260250

261251

262-
263252
Data Types That Support Iterators
264253
---------------------------------
265254

@@ -326,7 +315,6 @@ elements::
326315
13
327316

328317

329-
330318
Generator expressions and list comprehensions
331319
=============================================
332320

@@ -440,7 +428,7 @@ Generators are a special class of functions that simplify the task of writing
440428
iterators. Regular functions compute a value and return it, but generators
441429
return an iterator that returns a stream of values.
442430

443-
You're doubtless familiar with how regular function calls work in Python or C.
431+
You may be familiar with how regular function calls work in Python or C.
444432
When you call a function, it gets a private namespace where its local variables
445433
are created. When the function reaches a ``return`` statement, the local
446434
variables are destroyed and the value is returned to the caller. A later call
@@ -529,18 +517,15 @@ Passing values into a generator
529517

530518
In Python 2.4 and earlier, generators only produced output. Once a generator's
531519
code was invoked to create an iterator, there was no way to pass any new
532-
information into the function when its execution is resumed. You could hack
533-
together this ability by making the generator look at a global variable or by
534-
passing in some mutable object that callers then modify, but these approaches
535-
are messy.
520+
information into the function when its execution is resumed.
536521

537-
In Python 2.5 there's a simple way to pass values into a generator.
538-
:keyword:`yield` became an expression, returning a value that can be assigned to
539-
a variable or otherwise operated on::
522+
In Python 2.5, :keyword:`yield` became an expression, returning a value that
523+
can be assigned to a variable or otherwise operated on, providing a simple
524+
way to pass values into a generator::
540525

541526
val = (yield i)
542527

543-
I recommend that you **always** put parentheses around a ``yield`` expression
528+
It's recommended that you **always** put parentheses around a ``yield`` expression
544529
when you're doing something with the returned value, as in the above example.
545530
The parentheses aren't always necessary, but it's easier to always add them
546531
instead of having to remember when they're needed.
@@ -608,8 +593,8 @@ generators:
608593
will also be called by Python's garbage collector when the generator is
609594
garbage-collected.
610595

611-
If you need to run cleanup code when a :exc:`GeneratorExit` occurs, I suggest
612-
using a ``try: ... finally:`` suite instead of catching :exc:`GeneratorExit`.
596+
If you need to run cleanup code when a :exc:`GeneratorExit` occurs, it's recommended
597+
to us a ``try: ... finally:`` suite instead of catching :exc:`GeneratorExit`.
613598

614599
The cumulative effect of these changes is to turn generators from one-way
615600
producers of information into both producers and consumers.
@@ -639,7 +624,7 @@ features of generator expressions:
639624
>>> [upper(s) for s in ['sentence', 'fragment']]
640625
['SENTENCE', 'FRAGMENT']
641626

642-
You can of course achieve the same effect with a list comprehension.
627+
(You can achieve the same effect with a list comprehension.)
643628

644629
:func:`filter(predicate, iter) <filter>` returns an iterator over all the
645630
sequence elements that meet a certain condition, and is similarly duplicated by
@@ -1131,20 +1116,21 @@ usual way::
11311116
def print_assign(name, value):
11321117
return name + '=' + str(value)
11331118

1134-
Which alternative is preferable? That's a style question; my usual course is to
1135-
avoid using ``lambda``.
1119+
Which alternative is preferable? That's mostly a question of style.
11361120

1137-
One reason for my preference is that ``lambda`` is quite limited in the
1121+
You may wish to avoid using ``lambda``, as there are limits to the
11381122
functions it can define. The result has to be computable as a single
11391123
expression, which means you can't have multiway ``if... elif... else``
11401124
comparisons or ``try... except`` statements. If you try to do too much in a
11411125
``lambda`` statement, you'll end up with an overly complicated expression that's
1142-
hard to read. Quick, what's the following code doing? ::
1126+
hard to read.
1127+
1128+
Consider::
11431129

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

1147-
You can figure it out, but it takes time to disentangle the expression to figure
1133+
It takes some mental effort to disentangle the expression to figure
11481134
out what's going on. Using a short nested ``def`` statements makes things a
11491135
little bit better::
11501136

@@ -1154,7 +1140,7 @@ little bit better::
11541140

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

1157-
But it would be best of all if I had simply used a ``for`` loop::
1143+
But it would be best of all would have been to use a ``for`` loop::
11581144

11591145
total = 0
11601146
for a, b in items:
@@ -1166,19 +1152,6 @@ Or the :func:`sum` built-in and a generator expression::
11661152

11671153
Many uses of :func:`functools.reduce` are clearer when written as ``for`` loops.
11681154

1169-
Fredrik Lundh once suggested the following set of rules for refactoring uses of
1170-
``lambda``:
1171-
1172-
1. Write a lambda function.
1173-
2. Write a comment explaining what the heck that lambda does.
1174-
3. Study the comment for a while, and think of a name that captures the essence
1175-
of the comment.
1176-
4. Convert the lambda to a def statement, using that name.
1177-
5. Remove the comment.
1178-
1179-
I really like these rules, but you're free to disagree
1180-
about whether this lambda-free style is better.
1181-
11821155

11831156
Revision History and Acknowledgements
11841157
=====================================

0 commit comments

Comments
 (0)