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