functional.py 0.6 - Functional Programming in Python
I'm pleased to announce the release of functional.py version 0.6, released under the GNU LGPL. functional.py can be obtained from: http://sourceforge.net/projects/xoltar-toolkit/ functional.py provides support for a functional style of Python programming. It includes support for closures, curried functions, lazy expressions, lazy tuples (functional programming languages call these lazy lists, but since lists are mutable in Python, tuples are closer in meaning), and lazy equivalents for map, filter, reduce, and zip. Also some higher order functions for composing functions and such. This release fixes a problem that prevented zero length LazyTuples (thanks to Alex Martelli for catching this one). It also adds several new functions or functors: class sequential: """ Take a number of functions, and when called, call each of them in turn. The first function in the list is the "main", or significant function, and the others are taken for side effects only. Their return values do not affect the return value of the also function, and any errors they raise are silently disregarded. If a function is explicitly specified via the *main* parameter, that function will be the one whose return value is used, regardless of where in the sequence it appears. Example: >>> def one(): ... print "one" ... return 1 ... >>> def two(): ... print "two" ... return 2 ... >>> def three(): ... print "three" ... return 3 ... >>> x = one() one >>> x 1 >>> x = sequential([one, two, three])() one two three >>> x 1 >>> >>> x = sequential([one, two, three], main = three)() one two three >>> x 3 >>> """ def also(*args): """ Handles the common case for **sequential**, in which the first function passed is the significant one. It takes free arguments instead of a single sequence argument. Example: >>> def one(): ... print "one" ... return 1 ... >>> def two(): ... print "two" ... return 2 ... >>> def three(): ... print "three" ... return 3 ... >>> one() one 1 >>> x = one() one >>> x 1 >>> x = also(one, two, three)() one two three >>> x 1 >>> x = also(two, one, three)() two one three """ class always: """ Returns a callable which always returns a given object. Example: >>> f = always(5) >>> f() 5 >>> """ class any_args: """ Returns a callable which will take any arguments, and ignore them, calling *func* with no arguments. Useful with map(), or in the common case of GUI event handlers which need to accept an event parameter, but do not use it. Example: >>> def return5(): ... return 5 ... >>> return5("unneeded", "unnecessary") Traceback (innermost last): File "<stdin>", line 1, in ? TypeError: no arguments expected >>> f = any_args(return5) >>> f("unneeded", "unnecessary") 5 >>> """ class with_error: """ Takes a function, and an error-handler function. When called, the first function will be called. Any errors will cause the error function to be called with sys.exc_info() as the argument, *and the return value of the error handler will be returned.* If the error-handler function re-raises the exception (or another), the exception will propagate back to the caller. It is possible to chain error-handlers together with **atempt**, below. Example: >>> from operator import div >>> div(1/0) Traceback (innermost last): File "<stdin>", line 1, in ? ZeroDivisionError: integer division or modulo >>> def recover(exc): ... return sys.maxint ... >>> safediv = with_error(div, recover) >>> safediv(1, 0) 2147483647 >>> """ class attempt: """ Given a function sequence, attempt to call and return each in turn. The return value of the first function to successfully return is returned. This could be used to implement something like the pattern matching techniques used in functional languages. A common use would be attaching error handlers to functions after the fact. Suppose we want a want a version of the div() function that returns sys.maxint when we attempt to divide by zero, and zero if we attempt to divide by something other than a number as in this example: >>> def zeroHandler(exc_info): ... exc = exc_info[1] ... if isinstance(exc, ZeroDivisionError): ... return sys.maxint ... else: ... raise ... >>> safediv = with_error(div, zeroHandler) >>> safediv(1, 0) 2147483647 >>> def typeHandler(exc_info): ... exc = exc_info[1] ... if isinstance(exc, TypeError): ... return 0 ... else: ... raise ... >>> safediv = with_error(div, attempt(zeroHandler, typeHandler)) >>> safediv(1,0) 2147483647 >>> safediv(1, "abc") 0 >>> """ -- Bryn Keller xoltar@starship.python.net
participants (1)
-
Bryn Keller