blob: 5a5533929010332691fb6af9cb45fb3cffadf8d8 [file] [log] [blame]
Thomas Wouters89f507f2006-12-13 04:49:30 +00001Functional Programming HOWTO
2================================
3
4**Version 0.30**
5
6(This is a first draft. Please send comments/error
7reports/suggestions to amk@amk.ca. This URL is probably not going to
8be the final location of the document, so be careful about linking to
9it -- you may want to add a disclaimer.)
10
11In this document, we'll take a tour of Python's features suitable for
12implementing programs in a functional style. After an introduction to
13the concepts of functional programming, we'll look at language
14features such as iterators and generators and relevant library modules
15such as ``itertools`` and ``functools``.
16
17
18.. contents::
19
20Introduction
21----------------------
22
23This section explains the basic concept of functional programming; if
24you're just interested in learning about Python language features,
25skip to the next section.
26
27Programming languages support decomposing problems in several different
28ways:
29
30* Most programming languages are **procedural**:
31 programs are lists of instructions that tell the computer what to
32 do with the program's input.
33 C, Pascal, and even Unix shells are procedural languages.
34
35* In **declarative** languages, you write a specification that describes
36 the problem to be solved, and the language implementation figures out
37 how to perform the computation efficiently. SQL is the declarative
38 language you're most likely to be familiar with; a SQL query describes
39 the data set you want to retrieve, and the SQL engine decides whether to
40 scan tables or use indexes, which subclauses should be performed first,
41 etc.
42
43* **Object-oriented** programs manipulate collections of objects.
44 Objects have internal state and support methods that query or modify
45 this internal state in some way. Smalltalk and Java are
46 object-oriented languages. C++ and Python are languages that
47 support object-oriented programming, but don't force the use
48 of object-oriented features.
49
50* **Functional** programming decomposes a problem into a set of functions.
51 Ideally, functions only take inputs and produce outputs, and don't have any
52 internal state that affects the output produced for a given input.
53 Well-known functional languages include the ML family (Standard ML,
54 OCaml, and other variants) and Haskell.
55
56The designers of some computer languages have chosen one approach to
57programming that's emphasized. This often makes it difficult to
58write programs that use a different approach. Other languages are
59multi-paradigm languages that support several different approaches. Lisp,
60C++, and Python are multi-paradigm; you can write programs or
61libraries that are largely procedural, object-oriented, or functional
62in all of these languages. In a large program, different sections
63might be written using different approaches; the GUI might be object-oriented
64while the processing logic is procedural or functional, for example.
65
66In a functional program, input flows through a set of functions. Each
67function operates on its input and produces some output. Functional
68style frowns upon functions with side effects that modify internal
69state or make other changes that aren't visible in the function's
70return value. Functions that have no side effects at all are
71called **purely functional**.
72Avoiding side effects means not using data structures
73that get updated as a program runs; every function's output
74must only depend on its input.
75
76Some languages are very strict about purity and don't even have
77assignment statements such as ``a=3`` or ``c = a + b``, but it's
78difficult to avoid all side effects. Printing to the screen or
79writing to a disk file are side effects, for example. For example, in
80Python a ``print`` statement or a ``time.sleep(1)`` both return no
81useful value; they're only called for their side effects of sending
82some text to the screen or pausing execution for a second.
83
84Python programs written in functional style usually won't go to the
85extreme of avoiding all I/O or all assignments; instead, they'll
86provide a functional-appearing interface but will use non-functional
87features internally. For example, the implementation of a function
88will still use assignments to local variables, but won't modify global
89variables or have other side effects.
90
91Functional programming can be considered the opposite of
92object-oriented programming. Objects are little capsules containing
93some internal state along with a collection of method calls that let
94you modify this state, and programs consist of making the right set of
95state changes. Functional programming wants to avoid state changes as
96much as possible and works with data flowing between functions. In
97Python you might combine the two approaches by writing functions that
98take and return instances representing objects in your application
99(e-mail messages, transactions, etc.).
100
101Functional design may seem like an odd constraint to work under. Why
102should you avoid objects and side effects? There are theoretical and
103practical advantages to the functional style:
104
105* Formal provability.
106* Modularity.
107* Composability.
108* Ease of debugging and testing.
109
110Formal provability
111''''''''''''''''''''''
112
113A theoretical benefit is that it's easier to construct a mathematical proof
114that a functional program is correct.
115
116For a long time researchers have been interested in finding ways to
117mathematically prove programs correct. This is different from testing
118a program on numerous inputs and concluding that its output is usually
119correct, or reading a program's source code and concluding that the
120code looks right; the goal is instead a rigorous proof that a program
121produces the right result for all possible inputs.
122
123The technique used to prove programs correct is to write down
124**invariants**, properties of the input data and of the program's
125variables that are always true. For each line of code, you then show
126that if invariants X and Y are true **before** the line is executed,
127the slightly different invariants X' and Y' are true **after**
128the line is executed. This continues until you reach the end of the
129program, at which point the invariants should match the desired
130conditions on the program's output.
131
132Functional programming's avoidance of assignments arose because
133assignments are difficult to handle with this technique;
134assignments can break invariants that were true before the assignment
135without producing any new invariants that can be propagated onward.
136
137Unfortunately, proving programs correct is largely impractical and not
138relevant to Python software. Even trivial programs require proofs that
139are several pages long; the proof of correctness for a moderately
140complicated program would be enormous, and few or none of the programs
141you use daily (the Python interpreter, your XML parser, your web
142browser) could be proven correct. Even if you wrote down or generated
143a proof, there would then be the question of verifying the proof;
144maybe there's an error in it, and you wrongly believe you've proved
145the program correct.
146
147Modularity
148''''''''''''''''''''''
149
150A more practical benefit of functional programming is that it forces
151you to break apart your problem into small pieces. Programs are more
152modular as a result. It's easier to specify and write a small
153function that does one thing than a large function that performs a
154complicated transformation. Small functions are also easier to read
155and to check for errors.
156
157
158Ease of debugging and testing
159''''''''''''''''''''''''''''''''''
160
161Testing and debugging a functional-style program is easier.
162
163Debugging is simplified because functions are generally small and
164clearly specified. When a program doesn't work, each function is an
165interface point where you can check that the data are correct. You
166can look at the intermediate inputs and outputs to quickly isolate the
167function that's responsible for a bug.
168
169Testing is easier because each function is a potential subject for a
170unit test. Functions don't depend on system state that needs to be
171replicated before running a test; instead you only have to synthesize
172the right input and then check that the output matches expectations.
173
174
175
176Composability
177''''''''''''''''''''''
178
179As you work on a functional-style program, you'll write a number of
180functions with varying inputs and outputs. Some of these functions
181will be unavoidably specialized to a particular application, but
182others will be useful in a wide variety of programs. For example, a
183function that takes a directory path and returns all the XML files in
184the directory, or a function that takes a filename and returns its
185contents, can be applied to many different situations.
186
187Over time you'll form a personal library of utilities. Often you'll
188assemble new programs by arranging existing functions in a new
189configuration and writing a few functions specialized for the current
190task.
191
192
193
194Iterators
195-----------------------
196
197I'll start by looking at a Python language feature that's an important
198foundation for writing functional-style programs: iterators.
199
200An iterator is an object representing a stream of data; this object
201returns the data one element at a time. A Python iterator must
Georg Brandla18af4e2007-04-21 15:47:16 +0000202support a method called ``__next__()`` that takes no arguments and always
Thomas Wouters89f507f2006-12-13 04:49:30 +0000203returns the next element of the stream. If there are no more elements
Georg Brandla18af4e2007-04-21 15:47:16 +0000204in the stream, ``__next__()`` must raise the ``StopIteration`` exception.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000205Iterators don't have to be finite, though; it's perfectly reasonable
206to write an iterator that produces an infinite stream of data.
Georg Brandla18af4e2007-04-21 15:47:16 +0000207The built-in ``next()`` function is normally used to call the iterator's
208``__next__()`` method.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000209
210The built-in ``iter()`` function takes an arbitrary object and tries
211to return an iterator that will return the object's contents or
212elements, raising ``TypeError`` if the object doesn't support
213iteration. Several of Python's built-in data types support iteration,
214the most common being lists and dictionaries. An object is called
215an **iterable** object if you can get an iterator for it.
216
217You can experiment with the iteration interface manually::
218
219 >>> L = [1,2,3]
220 >>> it = iter(L)
221 >>> print it
222 <iterator object at 0x8116870>
Georg Brandla18af4e2007-04-21 15:47:16 +0000223 >>> next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000224 1
Georg Brandla18af4e2007-04-21 15:47:16 +0000225 >>> next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000226 2
Georg Brandla18af4e2007-04-21 15:47:16 +0000227 >>> next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000228 3
Georg Brandla18af4e2007-04-21 15:47:16 +0000229 >>> next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000230 Traceback (most recent call last):
231 File "<stdin>", line 1, in ?
232 StopIteration
233 >>>
234
235Python expects iterable objects in several different contexts, the
236most important being the ``for`` statement. In the statement ``for X in Y``,
237Y must be an iterator or some object for which ``iter()`` can create
238an iterator. These two statements are equivalent::
239
240 for i in iter(obj):
241 print i
242
243 for i in obj:
244 print i
245
246Iterators can be materialized as lists or tuples by using the
247``list()`` or ``tuple()`` constructor functions::
248
249 >>> L = [1,2,3]
250 >>> iterator = iter(L)
251 >>> t = tuple(iterator)
252 >>> t
253 (1, 2, 3)
254
255Sequence unpacking also supports iterators: if you know an iterator
256will return N elements, you can unpack them into an N-tuple::
257
258 >>> L = [1,2,3]
259 >>> iterator = iter(L)
260 >>> a,b,c = iterator
261 >>> a,b,c
262 (1, 2, 3)
263
264Built-in functions such as ``max()`` and ``min()`` can take a single
265iterator argument and will return the largest or smallest element.
266The ``"in"`` and ``"not in"`` operators also support iterators: ``X in
267iterator`` is true if X is found in the stream returned by the
268iterator. You'll run into obvious problems if the iterator is
269infinite; ``max()``, ``min()``, and ``"not in"`` will never return, and
270if the element X never appears in the stream, the ``"in"`` operator
271won't return either.
272
273Note that you can only go forward in an iterator; there's no way to
274get the previous element, reset the iterator, or make a copy of it.
275Iterator objects can optionally provide these additional capabilities,
Georg Brandla18af4e2007-04-21 15:47:16 +0000276but the iterator protocol only specifies the ``__next__()`` method.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000277Functions may therefore consume all of the iterator's output, and if
278you need to do something different with the same stream, you'll have
279to create a new iterator.
280
281
282
283Data Types That Support Iterators
284'''''''''''''''''''''''''''''''''''
285
286We've already seen how lists and tuples support iterators. In fact,
287any Python sequence type, such as strings, will automatically support
288creation of an iterator.
289
290Calling ``iter()`` on a dictionary returns an iterator that will loop
291over the dictionary's keys::
292
293 >>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
294 ... 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12}
295 >>> for key in m:
296 ... print key, m[key]
297 Mar 3
298 Feb 2
299 Aug 8
300 Sep 9
301 May 5
302 Jun 6
303 Jul 7
304 Jan 1
305 Apr 4
306 Nov 11
307 Dec 12
308 Oct 10
309
310Note that the order is essentially random, because it's based on the
311hash ordering of the objects in the dictionary.
312
313Applying ``iter()`` to a dictionary always loops over the keys, but
314dictionaries have methods that return other iterators. If you want to
315iterate over keys, values, or key/value pairs, you can explicitly call
316the ``iterkeys()``, ``itervalues()``, or ``iteritems()`` methods to
317get an appropriate iterator.
318
319The ``dict()`` constructor can accept an iterator that returns a
320finite stream of ``(key, value)`` tuples::
321
322 >>> L = [('Italy', 'Rome'), ('France', 'Paris'), ('US', 'Washington DC')]
323 >>> dict(iter(L))
324 {'Italy': 'Rome', 'US': 'Washington DC', 'France': 'Paris'}
325
326Files also support iteration by calling the ``readline()``
327method until there are no more lines in the file. This means you can
328read each line of a file like this::
329
330 for line in file:
331 # do something for each line
332 ...
333
334Sets can take their contents from an iterable and let you iterate over
335the set's elements::
336
337 S = set((2, 3, 5, 7, 11, 13))
338 for i in S:
339 print i
340
341
342
343Generator expressions and list comprehensions
344----------------------------------------------------
345
346Two common operations on an iterator's output are 1) performing some
347operation for every element, 2) selecting a subset of elements that
348meet some condition. For example, given a list of strings, you might
349want to strip off trailing whitespace from each line or extract all
350the strings containing a given substring.
351
352List comprehensions and generator expressions (short form: "listcomps"
353and "genexps") are a concise notation for such operations, borrowed
354from the functional programming language Haskell
355(http://www.haskell.org). You can strip all the whitespace from a
356stream of strings with the following code::
357
358 line_list = [' line 1\n', 'line 2 \n', ...]
359
360 # Generator expression -- returns iterator
361 stripped_iter = (line.strip() for line in line_list)
362
363 # List comprehension -- returns list
364 stripped_list = [line.strip() for line in line_list]
365
366You can select only certain elements by adding an ``"if"`` condition::
367
368 stripped_list = [line.strip() for line in line_list
369 if line != ""]
370
371With a list comprehension, you get back a Python list;
372``stripped_list`` is a list containing the resulting lines, not an
373iterator. Generator expressions return an iterator that computes the
374values as necessary, not needing to materialize all the values at
375once. This means that list comprehensions aren't useful if you're
376working with iterators that return an infinite stream or a very large
377amount of data. Generator expressions are preferable in these
378situations.
379
380Generator expressions are surrounded by parentheses ("()") and list
381comprehensions are surrounded by square brackets ("[]"). Generator
382expressions have the form::
383
384 ( expression for expr in sequence1
385 if condition1
386 for expr2 in sequence2
387 if condition2
388 for expr3 in sequence3 ...
389 if condition3
390 for exprN in sequenceN
391 if conditionN )
392
393Again, for a list comprehension only the outside brackets are
394different (square brackets instead of parentheses).
395
396The elements of the generated output will be the successive values of
397``expression``. The ``if`` clauses are all optional; if present,
398``expression`` is only evaluated and added to the result when
399``condition`` is true.
400
401Generator expressions always have to be written inside parentheses,
402but the parentheses signalling a function call also count. If you
403want to create an iterator that will be immediately passed to a
404function you can write::
405
406 obj_total = sum(obj.count for obj in list_all_objects())
407
408The ``for...in`` clauses contain the sequences to be iterated over.
409The sequences do not have to be the same length, because they are
410iterated over from left to right, **not** in parallel. For each
411element in ``sequence1``, ``sequence2`` is looped over from the
412beginning. ``sequence3`` is then looped over for each
413resulting pair of elements from ``sequence1`` and ``sequence2``.
414
415To put it another way, a list comprehension or generator expression is
416equivalent to the following Python code::
417
418 for expr1 in sequence1:
419 if not (condition1):
420 continue # Skip this element
421 for expr2 in sequence2:
422 if not (condition2):
423 continue # Skip this element
424 ...
425 for exprN in sequenceN:
426 if not (conditionN):
427 continue # Skip this element
428
429 # Output the value of
430 # the expression.
431
432This means that when there are multiple ``for...in`` clauses but no
433``if`` clauses, the length of the resulting output will be equal to
434the product of the lengths of all the sequences. If you have two
435lists of length 3, the output list is 9 elements long::
436
437 seq1 = 'abc'
438 seq2 = (1,2,3)
439 >>> [ (x,y) for x in seq1 for y in seq2]
440 [('a', 1), ('a', 2), ('a', 3),
441 ('b', 1), ('b', 2), ('b', 3),
442 ('c', 1), ('c', 2), ('c', 3)]
443
444To avoid introducing an ambiguity into Python's grammar, if
445``expression`` is creating a tuple, it must be surrounded with
446parentheses. The first list comprehension below is a syntax error,
447while the second one is correct::
448
449 # Syntax error
450 [ x,y for x in seq1 for y in seq2]
451 # Correct
452 [ (x,y) for x in seq1 for y in seq2]
453
454
455Generators
456-----------------------
457
458Generators are a special class of functions that simplify the task of
459writing iterators. Regular functions compute a value and return it,
460but generators return an iterator that returns a stream of values.
461
462You're doubtless familiar with how regular function calls work in
463Python or C. When you call a function, it gets a private namespace
464where its local variables are created. When the function reaches a
465``return`` statement, the local variables are destroyed and the
466value is returned to the caller. A later call to the same function
467creates a new private namespace and a fresh set of local
468variables. But, what if the local variables weren't thrown away on
469exiting a function? What if you could later resume the function where
470it left off? This is what generators provide; they can be thought of
471as resumable functions.
472
473Here's the simplest example of a generator function::
474
475 def generate_ints(N):
476 for i in range(N):
477 yield i
478
479Any function containing a ``yield`` keyword is a generator function;
480this is detected by Python's bytecode compiler which compiles the
481function specially as a result.
482
483When you call a generator function, it doesn't return a single value;
484instead it returns a generator object that supports the iterator
485protocol. On executing the ``yield`` expression, the generator
486outputs the value of ``i``, similar to a ``return``
487statement. The big difference between ``yield`` and a
488``return`` statement is that on reaching a ``yield`` the
489generator's state of execution is suspended and local variables are
Georg Brandla18af4e2007-04-21 15:47:16 +0000490preserved. On the next call ``next(generator)``,
Thomas Wouters89f507f2006-12-13 04:49:30 +0000491the function will resume executing.
492
493Here's a sample usage of the ``generate_ints()`` generator::
494
495 >>> gen = generate_ints(3)
496 >>> gen
497 <generator object at 0x8117f90>
Georg Brandla18af4e2007-04-21 15:47:16 +0000498 >>> next(gen)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000499 0
Georg Brandla18af4e2007-04-21 15:47:16 +0000500 >>> next(gen)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000501 1
Georg Brandla18af4e2007-04-21 15:47:16 +0000502 >>> next(gen)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000503 2
Georg Brandla18af4e2007-04-21 15:47:16 +0000504 >>> next(gen)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000505 Traceback (most recent call last):
506 File "stdin", line 1, in ?
507 File "stdin", line 2, in generate_ints
508 StopIteration
509
510You could equally write ``for i in generate_ints(5)``, or
511``a,b,c = generate_ints(3)``.
512
513Inside a generator function, the ``return`` statement can only be used
514without a value, and signals the end of the procession of values;
515after executing a ``return`` the generator cannot return any further
516values. ``return`` with a value, such as ``return 5``, is a syntax
517error inside a generator function. The end of the generator's results
518can also be indicated by raising ``StopIteration`` manually, or by
519just letting the flow of execution fall off the bottom of the
520function.
521
522You could achieve the effect of generators manually by writing your
523own class and storing all the local variables of the generator as
524instance variables. For example, returning a list of integers could
525be done by setting ``self.count`` to 0, and having the
Georg Brandla18af4e2007-04-21 15:47:16 +0000526``__next__()`` method increment ``self.count`` and return it.
Thomas Wouters89f507f2006-12-13 04:49:30 +0000527However, for a moderately complicated generator, writing a
528corresponding class can be much messier.
529
530The test suite included with Python's library, ``test_generators.py``,
531contains a number of more interesting examples. Here's one generator
532that implements an in-order traversal of a tree using generators
533recursively.
534
535::
536
537 # A recursive generator that generates Tree leaves in in-order.
538 def inorder(t):
539 if t:
540 for x in inorder(t.left):
541 yield x
542
543 yield t.label
544
545 for x in inorder(t.right):
546 yield x
547
548Two other examples in ``test_generators.py`` produce
549solutions for the N-Queens problem (placing N queens on an NxN
550chess board so that no queen threatens another) and the Knight's Tour
551(finding a route that takes a knight to every square of an NxN chessboard
552without visiting any square twice).
553
554
555
556Passing values into a generator
557''''''''''''''''''''''''''''''''''''''''''''''
558
559In Python 2.4 and earlier, generators only produced output. Once a
560generator's code was invoked to create an iterator, there was no way to
561pass any new information into the function when its execution is
562resumed. You could hack together this ability by making the
563generator look at a global variable or by passing in some mutable object
564that callers then modify, but these approaches are messy.
565
566In Python 2.5 there's a simple way to pass values into a generator.
567``yield`` became an expression, returning a value that can be assigned
568to a variable or otherwise operated on::
569
570 val = (yield i)
571
572I recommend that you **always** put parentheses around a ``yield``
573expression when you're doing something with the returned value, as in
574the above example. The parentheses aren't always necessary, but it's
575easier to always add them instead of having to remember when they're
576needed.
577
578(PEP 342 explains the exact rules, which are that a
579``yield``-expression must always be parenthesized except when it
580occurs at the top-level expression on the right-hand side of an
581assignment. This means you can write ``val = yield i`` but have to
582use parentheses when there's an operation, as in ``val = (yield i)
583+ 12``.)
584
585Values are sent into a generator by calling its
586``send(value)`` method. This method resumes the
587generator's code and the ``yield`` expression returns the specified
Georg Brandla18af4e2007-04-21 15:47:16 +0000588value. If the regular ``__next__()`` method is called, the
Thomas Wouters89f507f2006-12-13 04:49:30 +0000589``yield`` returns ``None``.
590
591Here's a simple counter that increments by 1 and allows changing the
592value of the internal counter.
593
594::
595
596 def counter (maximum):
597 i = 0
598 while i < maximum:
599 val = (yield i)
600 # If value provided, change counter
601 if val is not None:
602 i = val
603 else:
604 i += 1
605
606And here's an example of changing the counter:
607
608 >>> it = counter(10)
Georg Brandla18af4e2007-04-21 15:47:16 +0000609 >>> print next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000610 0
Georg Brandla18af4e2007-04-21 15:47:16 +0000611 >>> print next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000612 1
613 >>> print it.send(8)
614 8
Georg Brandla18af4e2007-04-21 15:47:16 +0000615 >>> print next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000616 9
Georg Brandla18af4e2007-04-21 15:47:16 +0000617 >>> print next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000618 Traceback (most recent call last):
619 File ``t.py'', line 15, in ?
Georg Brandla18af4e2007-04-21 15:47:16 +0000620 print next(it)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000621 StopIteration
622
623Because ``yield`` will often be returning ``None``, you
624should always check for this case. Don't just use its value in
625expressions unless you're sure that the ``send()`` method
626will be the only method used resume your generator function.
627
628In addition to ``send()``, there are two other new methods on
629generators:
630
631* ``throw(type, value=None, traceback=None)`` is used to raise an exception inside the
632 generator; the exception is raised by the ``yield`` expression
633 where the generator's execution is paused.
634
635* ``close()`` raises a ``GeneratorExit``
636 exception inside the generator to terminate the iteration.
637 On receiving this
638 exception, the generator's code must either raise
639 ``GeneratorExit`` or ``StopIteration``; catching the
640 exception and doing anything else is illegal and will trigger
641 a ``RuntimeError``. ``close()`` will also be called by
642 Python's garbage collector when the generator is garbage-collected.
643
644 If you need to run cleanup code when a ``GeneratorExit`` occurs,
645 I suggest using a ``try: ... finally:`` suite instead of
646 catching ``GeneratorExit``.
647
648The cumulative effect of these changes is to turn generators from
649one-way producers of information into both producers and consumers.
650
651Generators also become **coroutines**, a more generalized form of
652subroutines. Subroutines are entered at one point and exited at
653another point (the top of the function, and a ``return``
654statement), but coroutines can be entered, exited, and resumed at
655many different points (the ``yield`` statements).
656
657
658Built-in functions
659----------------------------------------------
660
661Let's look in more detail at built-in functions often used with iterators.
662
663Two Python's built-in functions, ``map()`` and ``filter()``, are
664somewhat obsolete; they duplicate the features of list comprehensions
665but return actual lists instead of iterators.
666
667``map(f, iterA, iterB, ...)`` returns a list containing ``f(iterA[0],
668iterB[0]), f(iterA[1], iterB[1]), f(iterA[2], iterB[2]), ...``.
669
670::
671
672 def upper(s):
673 return s.upper()
674 map(upper, ['sentence', 'fragment']) =>
675 ['SENTENCE', 'FRAGMENT']
676
677 [upper(s) for s in ['sentence', 'fragment']] =>
678 ['SENTENCE', 'FRAGMENT']
679
680As shown above, you can achieve the same effect with a list
681comprehension. The ``itertools.imap()`` function does the same thing
682but can handle infinite iterators; it'll be discussed later, in the section on
683the ``itertools`` module.
684
685``filter(predicate, iter)`` returns a list
686that contains all the sequence elements that meet a certain condition,
687and is similarly duplicated by list comprehensions.
688A **predicate** is a function that returns the truth value of
689some condition; for use with ``filter()``, the predicate must take a
690single value.
691
692::
693
694 def is_even(x):
695 return (x % 2) == 0
696
697 filter(is_even, range(10)) =>
698 [0, 2, 4, 6, 8]
699
700This can also be written as a list comprehension::
701
702 >>> [x for x in range(10) if is_even(x)]
703 [0, 2, 4, 6, 8]
704
705``filter()`` also has a counterpart in the ``itertools`` module,
706``itertools.ifilter()``, that returns an iterator and
707can therefore handle infinite sequences just as ``itertools.imap()`` can.
708
709``reduce(func, iter, [initial_value])`` doesn't have a counterpart in
710the ``itertools`` module because it cumulatively performs an operation
711on all the iterable's elements and therefore can't be applied to
712infinite iterables. ``func`` must be a function that takes two elements
713and returns a single value. ``reduce()`` takes the first two elements
714A and B returned by the iterator and calculates ``func(A, B)``. It
715then requests the third element, C, calculates ``func(func(A, B),
716C)``, combines this result with the fourth element returned, and
717continues until the iterable is exhausted. If the iterable returns no
718values at all, a ``TypeError`` exception is raised. If the initial
719value is supplied, it's used as a starting point and
720``func(initial_value, A)`` is the first calculation.
721
722::
723
724 import operator
725 reduce(operator.concat, ['A', 'BB', 'C']) =>
726 'ABBC'
727 reduce(operator.concat, []) =>
728 TypeError: reduce() of empty sequence with no initial value
729 reduce(operator.mul, [1,2,3], 1) =>
730 6
731 reduce(operator.mul, [], 1) =>
732 1
733
734If you use ``operator.add`` with ``reduce()``, you'll add up all the
735elements of the iterable. This case is so common that there's a special
736built-in called ``sum()`` to compute it::
737
738 reduce(operator.add, [1,2,3,4], 0) =>
739 10
740 sum([1,2,3,4]) =>
741 10
742 sum([]) =>
743 0
744
745For many uses of ``reduce()``, though, it can be clearer to just write
746the obvious ``for`` loop::
747
748 # Instead of:
749 product = reduce(operator.mul, [1,2,3], 1)
750
751 # You can write:
752 product = 1
753 for i in [1,2,3]:
754 product *= i
755
756
757``enumerate(iter)`` counts off the elements in the iterable, returning
7582-tuples containing the count and each element.
759
760::
761
762 enumerate(['subject', 'verb', 'object']) =>
763 (0, 'subject'), (1, 'verb'), (2, 'object')
764
765``enumerate()`` is often used when looping through a list
766and recording the indexes at which certain conditions are met::
767
768 f = open('data.txt', 'r')
769 for i, line in enumerate(f):
770 if line.strip() == '':
771 print 'Blank line at line #%i' % i
772
773``sorted(iterable, [cmp=None], [key=None], [reverse=False)``
774collects all the elements of the iterable into a list, sorts
775the list, and returns the sorted result. The ``cmp``, ``key``,
776and ``reverse`` arguments are passed through to the
777constructed list's ``.sort()`` method.
778
779::
780
781 import random
782 # Generate 8 random numbers between [0, 10000)
783 rand_list = random.sample(range(10000), 8)
784 rand_list =>
785 [769, 7953, 9828, 6431, 8442, 9878, 6213, 2207]
786 sorted(rand_list) =>
787 [769, 2207, 6213, 6431, 7953, 8442, 9828, 9878]
788 sorted(rand_list, reverse=True) =>
789 [9878, 9828, 8442, 7953, 6431, 6213, 2207, 769]
790
791(For a more detailed discussion of sorting, see the Sorting mini-HOWTO
792in the Python wiki at http://wiki.python.org/moin/HowTo/Sorting.)
793
794The ``any(iter)`` and ``all(iter)`` built-ins look at
795the truth values of an iterable's contents. ``any()`` returns
796True if any element in the iterable is a true value, and ``all()``
797returns True if all of the elements are true values::
798
799 any([0,1,0]) =>
800 True
801 any([0,0,0]) =>
802 False
803 any([1,1,1]) =>
804 True
805 all([0,1,0]) =>
806 False
807 all([0,0,0]) =>
808 False
809 all([1,1,1]) =>
810 True
811
812
813Small functions and the lambda statement
814----------------------------------------------
815
816When writing functional-style programs, you'll often need little
817functions that act as predicates or that combine elements in some way.
818
819If there's a Python built-in or a module function that's suitable, you
820don't need to define a new function at all::
821
822 stripped_lines = [line.strip() for line in lines]
823 existing_files = filter(os.path.exists, file_list)
824
825If the function you need doesn't exist, you need to write it. One way
826to write small functions is to use the ``lambda`` statement. ``lambda``
827takes a number of parameters and an expression combining these parameters,
828and creates a small function that returns the value of the expression::
829
830 lowercase = lambda x: x.lower()
831
832 print_assign = lambda name, value: name + '=' + str(value)
833
834 adder = lambda x, y: x+y
835
836An alternative is to just use the ``def`` statement and define a
837function in the usual way::
838
839 def lowercase(x):
840 return x.lower()
841
842 def print_assign(name, value):
843 return name + '=' + str(value)
844
845 def adder(x,y):
846 return x + y
847
848Which alternative is preferable? That's a style question; my usual
849course is to avoid using ``lambda``.
850
851One reason for my preference is that ``lambda`` is quite limited in
852the functions it can define. The result has to be computable as a
853single expression, which means you can't have multiway
854``if... elif... else`` comparisons or ``try... except`` statements.
855If you try to do too much in a ``lambda`` statement, you'll end up
856with an overly complicated expression that's hard to read. Quick,
857what's the following code doing?
858
859::
860
861 total = reduce(lambda a, b: (0, a[1] + b[1]), items)[1]
862
863You can figure it out, but it takes time to disentangle the expression
864to figure out what's going on. Using a short nested
865``def`` statements makes things a little bit better::
866
867 def combine (a, b):
868 return 0, a[1] + b[1]
869
870 total = reduce(combine, items)[1]
871
872But it would be best of all if I had simply used a ``for`` loop::
873
874 total = 0
875 for a, b in items:
876 total += b
877
878Or the ``sum()`` built-in and a generator expression::
879
880 total = sum(b for a,b in items)
881
882Many uses of ``reduce()`` are clearer when written as ``for`` loops.
883
884Fredrik Lundh once suggested the following set of rules for refactoring
885uses of ``lambda``:
886
8871) Write a lambda function.
8882) Write a comment explaining what the heck that lambda does.
8893) Study the comment for a while, and think of a name that captures
890 the essence of the comment.
8914) Convert the lambda to a def statement, using that name.
8925) Remove the comment.
893
894I really like these rules, but you're free to disagree that this
895lambda-free style is better.
896
897
898The itertools module
899-----------------------
900
901The ``itertools`` module contains a number of commonly-used iterators
902as well as functions for combining several iterators. This section
903will introduce the module's contents by showing small examples.
904
905The module's functions fall into a few broad classes:
906
907* Functions that create a new iterator based on an existing iterator.
908* Functions for treating an iterator's elements as function arguments.
909* Functions for selecting portions of an iterator's output.
910* A function for grouping an iterator's output.
911
912Creating new iterators
913''''''''''''''''''''''
914
915``itertools.count(n)`` returns an infinite stream of
916integers, increasing by 1 each time. You can optionally supply the
917starting number, which defaults to 0::
918
919 itertools.count() =>
920 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
921 itertools.count(10) =>
922 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...
923
924``itertools.cycle(iter)`` saves a copy of the contents of a provided
925iterable and returns a new iterator that returns its elements from
926first to last. The new iterator will repeat these elements infinitely.
927
928::
929
930 itertools.cycle([1,2,3,4,5]) =>
931 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...
932
933``itertools.repeat(elem, [n])`` returns the provided element ``n``
934times, or returns the element endlessly if ``n`` is not provided.
935
936::
937
938 itertools.repeat('abc') =>
939 abc, abc, abc, abc, abc, abc, abc, abc, abc, abc, ...
940 itertools.repeat('abc', 5) =>
941 abc, abc, abc, abc, abc
942
943``itertools.chain(iterA, iterB, ...)`` takes an arbitrary number of
944iterables as input, and returns all the elements of the first
945iterator, then all the elements of the second, and so on, until all of
946the iterables have been exhausted.
947
948::
949
950 itertools.chain(['a', 'b', 'c'], (1, 2, 3)) =>
951 a, b, c, 1, 2, 3
952
953``itertools.izip(iterA, iterB, ...)`` takes one element from each iterable
954and returns them in a tuple::
955
956 itertools.izip(['a', 'b', 'c'], (1, 2, 3)) =>
957 ('a', 1), ('b', 2), ('c', 3)
958
959It's similiar to the built-in ``zip()`` function, but doesn't
960construct an in-memory list and exhaust all the input iterators before
961returning; instead tuples are constructed and returned only if they're
962requested. (The technical term for this behaviour is
963`lazy evaluation <http://en.wikipedia.org/wiki/Lazy_evaluation>`__.)
964
965This iterator is intended to be used with iterables that are all of
966the same length. If the iterables are of different lengths, the
967resulting stream will be the same length as the shortest iterable.
968
969::
970
971 itertools.izip(['a', 'b'], (1, 2, 3)) =>
972 ('a', 1), ('b', 2)
973
974You should avoid doing this, though, because an element may be taken
975from the longer iterators and discarded. This means you can't go on
976to use the iterators further because you risk skipping a discarded
977element.
978
979``itertools.islice(iter, [start], stop, [step])`` returns a stream
980that's a slice of the iterator. With a single ``stop`` argument,
981it will return the first ``stop``
982elements. If you supply a starting index, you'll get ``stop-start``
Guido van Rossume7ba4952007-06-06 23:52:48 +0000983elements, and if you supply a value for ``step``, elements will be
Thomas Wouters89f507f2006-12-13 04:49:30 +0000984skipped accordingly. Unlike Python's string and list slicing, you
985can't use negative values for ``start``, ``stop``, or ``step``.
986
987::
988
989 itertools.islice(range(10), 8) =>
990 0, 1, 2, 3, 4, 5, 6, 7
991 itertools.islice(range(10), 2, 8) =>
992 2, 3, 4, 5, 6, 7
993 itertools.islice(range(10), 2, 8, 2) =>
994 2, 4, 6
995
996``itertools.tee(iter, [n])`` replicates an iterator; it returns ``n``
997independent iterators that will all return the contents of the source
998iterator. If you don't supply a value for ``n``, the default is 2.
999Replicating iterators requires saving some of the contents of the source
1000iterator, so this can consume significant memory if the iterator is large
1001and one of the new iterators is consumed more than the others.
1002
1003::
1004
1005 itertools.tee( itertools.count() ) =>
1006 iterA, iterB
1007
1008 where iterA ->
1009 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
1010
1011 and iterB ->
1012 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...
1013
1014
1015Calling functions on elements
1016'''''''''''''''''''''''''''''
1017
1018Two functions are used for calling other functions on the contents of an
1019iterable.
1020
1021``itertools.imap(f, iterA, iterB, ...)`` returns
1022a stream containing ``f(iterA[0], iterB[0]), f(iterA[1], iterB[1]),
1023f(iterA[2], iterB[2]), ...``::
1024
1025 itertools.imap(operator.add, [5, 6, 5], [1, 2, 3]) =>
1026 6, 8, 8
1027
1028The ``operator`` module contains a set of functions
1029corresponding to Python's operators. Some examples are
1030``operator.add(a, b)`` (adds two values),
1031``operator.ne(a, b)`` (same as ``a!=b``),
1032and
1033``operator.attrgetter('id')`` (returns a callable that
1034fetches the ``"id"`` attribute).
1035
1036``itertools.starmap(func, iter)`` assumes that the iterable will
1037return a stream of tuples, and calls ``f()`` using these tuples as the
1038arguments::
1039
1040 itertools.starmap(os.path.join,
1041 [('/usr', 'bin', 'java'), ('/bin', 'python'),
1042 ('/usr', 'bin', 'perl'),('/usr', 'bin', 'ruby')])
1043 =>
1044 /usr/bin/java, /bin/python, /usr/bin/perl, /usr/bin/ruby
1045
1046
1047Selecting elements
1048''''''''''''''''''
1049
1050Another group of functions chooses a subset of an iterator's elements
1051based on a predicate.
1052
1053``itertools.ifilter(predicate, iter)`` returns all the elements for
1054which the predicate returns true::
1055
1056 def is_even(x):
1057 return (x % 2) == 0
1058
1059 itertools.ifilter(is_even, itertools.count()) =>
1060 0, 2, 4, 6, 8, 10, 12, 14, ...
1061
1062``itertools.ifilterfalse(predicate, iter)`` is the opposite,
1063returning all elements for which the predicate returns false::
1064
1065 itertools.ifilterfalse(is_even, itertools.count()) =>
1066 1, 3, 5, 7, 9, 11, 13, 15, ...
1067
1068``itertools.takewhile(predicate, iter)`` returns elements for as long
1069as the predicate returns true. Once the predicate returns false,
1070the iterator will signal the end of its results.
1071
1072::
1073
1074 def less_than_10(x):
1075 return (x < 10)
1076
1077 itertools.takewhile(less_than_10, itertools.count()) =>
1078 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
1079
1080 itertools.takewhile(is_even, itertools.count()) =>
1081 0
1082
1083``itertools.dropwhile(predicate, iter)`` discards elements while the
1084predicate returns true, and then returns the rest of the iterable's
1085results.
1086
1087::
1088
1089 itertools.dropwhile(less_than_10, itertools.count()) =>
1090 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...
1091
1092 itertools.dropwhile(is_even, itertools.count()) =>
1093 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...
1094
1095
1096Grouping elements
1097'''''''''''''''''
1098
1099The last function I'll discuss, ``itertools.groupby(iter,
1100key_func=None)``, is the most complicated. ``key_func(elem)`` is a
1101function that can compute a key value for each element returned by the
1102iterable. If you don't supply a key function, the key is simply each
1103element itself.
1104
1105``groupby()`` collects all the consecutive elements from the
1106underlying iterable that have the same key value, and returns a stream
1107of 2-tuples containing a key value and an iterator for the elements
1108with that key.
1109
1110::
1111
1112 city_list = [('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL'),
1113 ('Anchorage', 'AK'), ('Nome', 'AK'),
1114 ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ'),
1115 ...
1116 ]
1117
1118 def get_state ((city, state)):
1119 return state
1120
1121 itertools.groupby(city_list, get_state) =>
1122 ('AL', iterator-1),
1123 ('AK', iterator-2),
1124 ('AZ', iterator-3), ...
1125
1126 where
1127 iterator-1 =>
1128 ('Decatur', 'AL'), ('Huntsville', 'AL'), ('Selma', 'AL')
1129 iterator-2 =>
1130 ('Anchorage', 'AK'), ('Nome', 'AK')
1131 iterator-3 =>
1132 ('Flagstaff', 'AZ'), ('Phoenix', 'AZ'), ('Tucson', 'AZ')
1133
1134``groupby()`` assumes that the underlying iterable's contents will
1135already be sorted based on the key. Note that the returned iterators
1136also use the underlying iterable, so you have to consume the results
1137of iterator-1 before requesting iterator-2 and its corresponding key.
1138
1139
1140The functools module
1141----------------------------------------------
1142
1143The ``functools`` module in Python 2.5 contains some higher-order
1144functions. A **higher-order function** takes one or more functions as
1145input and returns a new function. The most useful tool in this module
1146is the ``partial()`` function.
1147
1148For programs written in a functional style, you'll sometimes want to
1149construct variants of existing functions that have some of the
1150parameters filled in. Consider a Python function ``f(a, b, c)``; you
1151may wish to create a new function ``g(b, c)`` that's equivalent to
1152``f(1, b, c)``; you're filling in a value for one of ``f()``'s parameters.
1153This is called "partial function application".
1154
1155The constructor for ``partial`` takes the arguments ``(function, arg1,
1156arg2, ... kwarg1=value1, kwarg2=value2)``. The resulting object is
1157callable, so you can just call it to invoke ``function`` with the
1158filled-in arguments.
1159
1160Here's a small but realistic example::
1161
1162 import functools
1163
1164 def log (message, subsystem):
1165 "Write the contents of 'message' to the specified subsystem."
1166 print '%s: %s' % (subsystem, message)
1167 ...
1168
1169 server_log = functools.partial(log, subsystem='server')
1170 server_log('Unable to open socket')
1171
1172
1173The operator module
1174-------------------
1175
1176The ``operator`` module was mentioned earlier. It contains a set of
1177functions corresponding to Python's operators. These functions
1178are often useful in functional-style code because they save you
1179from writing trivial functions that perform a single operation.
1180
1181Some of the functions in this module are:
1182
1183* Math operations: ``add()``, ``sub()``, ``mul()``, ``div()``, ``floordiv()``,
1184 ``abs()``, ...
1185* Logical operations: ``not_()``, ``truth()``.
1186* Bitwise operations: ``and_()``, ``or_()``, ``invert()``.
1187* Comparisons: ``eq()``, ``ne()``, ``lt()``, ``le()``, ``gt()``, and ``ge()``.
1188* Object identity: ``is_()``, ``is_not()``.
1189
1190Consult `the operator module's documentation <http://docs.python.org/lib/module-operator.html>`__ for a complete
1191list.
1192
1193
1194
1195The functional module
1196---------------------
1197
1198Collin Winter's `functional module <http://oakwinter.com/code/functional/>`__
1199provides a number of more
1200advanced tools for functional programming. It also reimplements
1201several Python built-ins, trying to make them more intuitive to those
1202used to functional programming in other languages.
1203
1204This section contains an introduction to some of the most important
1205functions in ``functional``; full documentation can be found at `the
1206project's website <http://oakwinter.com/code/functional/documentation/>`__.
1207
1208``compose(outer, inner, unpack=False)``
1209
1210The ``compose()`` function implements function composition.
1211In other words, it returns a wrapper around the ``outer`` and ``inner`` callables, such
1212that the return value from ``inner`` is fed directly to ``outer``. That is,
1213
1214::
1215
1216 >>> def add(a, b):
1217 ... return a + b
1218 ...
1219 >>> def double(a):
1220 ... return 2 * a
1221 ...
1222 >>> compose(double, add)(5, 6)
1223 22
1224
1225is equivalent to
1226
1227::
1228
1229 >>> double(add(5, 6))
1230 22
1231
1232The ``unpack`` keyword is provided to work around the fact that Python functions are not always
1233`fully curried <http://en.wikipedia.org/wiki/Currying>`__.
1234By default, it is expected that the ``inner`` function will return a single object and that the ``outer``
1235function will take a single argument. Setting the ``unpack`` argument causes ``compose`` to expect a
1236tuple from ``inner`` which will be expanded before being passed to ``outer``. Put simply,
1237
1238::
1239
1240 compose(f, g)(5, 6)
1241
1242is equivalent to::
1243
1244 f(g(5, 6))
1245
1246while
1247
1248::
1249
1250 compose(f, g, unpack=True)(5, 6)
1251
1252is equivalent to::
1253
1254 f(*g(5, 6))
1255
1256Even though ``compose()`` only accepts two functions, it's trivial to
1257build up a version that will compose any number of functions. We'll
1258use ``reduce()``, ``compose()`` and ``partial()`` (the last of which
1259is provided by both ``functional`` and ``functools``).
1260
1261::
1262
1263 from functional import compose, partial
1264
1265 multi_compose = partial(reduce, compose)
1266
1267
1268We can also use ``map()``, ``compose()`` and ``partial()`` to craft a
1269version of ``"".join(...)`` that converts its arguments to string::
1270
1271 from functional import compose, partial
1272
1273 join = compose("".join, partial(map, str))
1274
1275
1276``flip(func)``
1277
1278``flip()`` wraps the callable in ``func`` and
1279causes it to receive its non-keyword arguments in reverse order.
1280
1281::
1282
1283 >>> def triple(a, b, c):
1284 ... return (a, b, c)
1285 ...
1286 >>> triple(5, 6, 7)
1287 (5, 6, 7)
1288 >>>
1289 >>> flipped_triple = flip(triple)
1290 >>> flipped_triple(5, 6, 7)
1291 (7, 6, 5)
1292
1293``foldl(func, start, iterable)``
1294
1295``foldl()`` takes a binary function, a starting value (usually some kind of 'zero'), and an iterable.
1296The function is applied to the starting value and the first element of the list, then the result of
1297that and the second element of the list, then the result of that and the third element of the list,
1298and so on.
1299
1300This means that a call such as::
1301
1302 foldl(f, 0, [1, 2, 3])
1303
1304is equivalent to::
1305
1306 f(f(f(0, 1), 2), 3)
1307
1308
1309``foldl()`` is roughly equivalent to the following recursive function::
1310
1311 def foldl(func, start, seq):
1312 if len(seq) == 0:
1313 return start
1314
1315 return foldl(func, func(start, seq[0]), seq[1:])
1316
1317Speaking of equivalence, the above ``foldl`` call can be expressed in terms of the built-in ``reduce`` like
1318so::
1319
1320 reduce(f, [1, 2, 3], 0)
1321
1322
1323We can use ``foldl()``, ``operator.concat()`` and ``partial()`` to
1324write a cleaner, more aesthetically-pleasing version of Python's
1325``"".join(...)`` idiom::
1326
1327 from functional import foldl, partial
1328 from operator import concat
1329
1330 join = partial(foldl, concat, "")
1331
1332
1333Revision History and Acknowledgements
1334------------------------------------------------
1335
1336The author would like to thank the following people for offering
1337suggestions, corrections and assistance with various drafts of this
1338article: Ian Bicking, Nick Coghlan, Nick Efford, Raymond Hettinger,
1339Jim Jewett, Mike Krell, Leandro Lameiro, Jussi Salmela,
1340Collin Winter, Blake Winton.
1341
1342Version 0.1: posted June 30 2006.
1343
1344Version 0.11: posted July 1 2006. Typo fixes.
1345
1346Version 0.2: posted July 10 2006. Merged genexp and listcomp
1347sections into one. Typo fixes.
1348
1349Version 0.21: Added more references suggested on the tutor mailing list.
1350
1351Version 0.30: Adds a section on the ``functional`` module written by
1352Collin Winter; adds short section on the operator module; a few other
1353edits.
1354
1355
1356References
1357--------------------
1358
1359General
1360'''''''''''''''
1361
1362**Structure and Interpretation of Computer Programs**, by
1363Harold Abelson and Gerald Jay Sussman with Julie Sussman.
1364Full text at http://mitpress.mit.edu/sicp/.
1365In this classic textbook of computer science, chapters 2 and 3 discuss the
1366use of sequences and streams to organize the data flow inside a
1367program. The book uses Scheme for its examples, but many of the
1368design approaches described in these chapters are applicable to
1369functional-style Python code.
1370
1371http://www.defmacro.org/ramblings/fp.html: A general
1372introduction to functional programming that uses Java examples
1373and has a lengthy historical introduction.
1374
1375http://en.wikipedia.org/wiki/Functional_programming:
1376General Wikipedia entry describing functional programming.
1377
1378http://en.wikipedia.org/wiki/Coroutine:
1379Entry for coroutines.
1380
1381http://en.wikipedia.org/wiki/Currying:
1382Entry for the concept of currying.
1383
1384Python-specific
1385'''''''''''''''''''''''''''
1386
1387http://gnosis.cx/TPiP/:
1388The first chapter of David Mertz's book :title-reference:`Text Processing in Python`
1389discusses functional programming for text processing, in the section titled
1390"Utilizing Higher-Order Functions in Text Processing".
1391
1392Mertz also wrote a 3-part series of articles on functional programming
1393for IBM's DeveloperWorks site; see
1394`part 1 <http://www-128.ibm.com/developerworks/library/l-prog.html>`__,
1395`part 2 <http://www-128.ibm.com/developerworks/library/l-prog2.html>`__, and
1396`part 3 <http://www-128.ibm.com/developerworks/linux/library/l-prog3.html>`__,
1397
1398
1399Python documentation
1400'''''''''''''''''''''''''''
1401
1402http://docs.python.org/lib/module-itertools.html:
Thomas Wouters902d6eb2007-01-09 23:18:33 +00001403Documentation for the ``itertools`` module.
Thomas Wouters89f507f2006-12-13 04:49:30 +00001404
1405http://docs.python.org/lib/module-operator.html:
Thomas Wouters902d6eb2007-01-09 23:18:33 +00001406Documentation for the ``operator`` module.
Thomas Wouters89f507f2006-12-13 04:49:30 +00001407
1408http://www.python.org/dev/peps/pep-0289/:
1409PEP 289: "Generator Expressions"
1410
1411http://www.python.org/dev/peps/pep-0342/
1412PEP 342: "Coroutines via Enhanced Generators" describes the new generator
1413features in Python 2.5.
1414
1415.. comment
1416
1417 Topics to place
1418 -----------------------------
1419
1420 XXX os.walk()
1421
1422 XXX Need a large example.
1423
1424 But will an example add much? I'll post a first draft and see
1425 what the comments say.
1426
1427.. comment
1428
1429 Original outline:
1430 Introduction
1431 Idea of FP
1432 Programs built out of functions
1433 Functions are strictly input-output, no internal state
1434 Opposed to OO programming, where objects have state
1435
1436 Why FP?
1437 Formal provability
1438 Assignment is difficult to reason about
1439 Not very relevant to Python
1440 Modularity
1441 Small functions that do one thing
1442 Debuggability:
1443 Easy to test due to lack of state
1444 Easy to verify output from intermediate steps
1445 Composability
1446 You assemble a toolbox of functions that can be mixed
1447
1448 Tackling a problem
1449 Need a significant example
1450
1451 Iterators
1452 Generators
1453 The itertools module
1454 List comprehensions
1455 Small functions and the lambda statement
1456 Built-in functions
1457 map
1458 filter
1459 reduce
1460
1461.. comment
1462
1463 Handy little function for printing part of an iterator -- used
1464 while writing this document.
1465
1466 import itertools
1467 def print_iter(it):
1468 slice = itertools.islice(it, 10)
1469 for elem in slice[:-1]:
1470 sys.stdout.write(str(elem))
1471 sys.stdout.write(', ')
1472 print elem[-1]
1473
1474