I never thought that Python would fall under the influence of functional languages, no matter what people say or think. I am familiar with imperative languages such as C and Algol68 and although I made functions as “first class” objects, I did not consider Python as a functional programming language. However, it was clear that users want more from lists and features.
List operations were applied to each list item and created a new list. For example:
def square(x): return x*x vals = [1, 2, 3, 4] newvals = [] for v in vals: newvals.append(square(v))
In functional languages such as Lisp and Scheme, operations such as this have been developed as built-in language functions. Thus, users familiar with such languages implemented similar functionality in Python. For example:
def map(f, s): result = [] for x in s: result.append(f(x)) return result def square(x): return x*x vals = [1, 2, 3, 4] newvals = map(square,vals)
The subtlety of the above code is that many people did not like the fact that the function is applied to the elements of the list as a set of separate functions. Languages such as Lisp allowed functions to be defined on the fly during mapping. For example, in Scheme you can create anonymous functions and perform mapping in a single expression, using lambda, as follows:
(map (lambda (x) (* xx)) '(1 2 3 4))
Although Python functions were objects of the “first class”, it had no such mechanism for creating anonymous functions.
In late 1993, users rushed around various ideas to create anonymous functions. For example, Mark Lutz wrote the code for a function that creates functions using exec:
def genfunc(args, expr): exec('def f(' + args + '): return ' + expr) return eval('f')
Tim Peters wrote a solution that simplified the syntax, allowing users to do the following:
vals = [1, 2, 3, 4] newvals = map(func('x: x*x'), vals)
It became clear that there really was a need for such functionality. At the same time, it seemed tempting to define anonymous functions as lines of code that a programmer must manually process through exec. Thus, in January 1994, the map (), filter (), and reduce () functions were added to the standard library. In addition, the lambda operator was introduced to create anonymous functions (as expressions) in a more direct syntax. For example:
vals = [1, 2, 3, 4] newvals = map(lambda x:x*x, vals)
These additions were essential at an early stage of development. Unfortunately, I do not remember the author, and the SVN logs did not record him. If this is your merit, leave a comment!
')
I never liked using lambda terminology, but due to the lack of a better and obvious alternative, it was adopted in Python. In the end, it was the choice of the now anonymous author, and at that time big changes required much less discussion than at present.
Lambda was really intended only to be syntactic sugar to define anonymous functions. However, this choice of terminology had many unintended consequences. For example, users familiar with functional languages expected the semantics of lambda to be consistent with other languages. As a result, they found that the Python implementation was very lacking in extended functionality. For example, the problem with lambda is that the supplied expression could not refer to variables in the surrounding context. For example, if you had this code, map () would break because the lambda function would work with an undefined reference to the variable 'a'.
def spam(s): a = 4 r = map(lambda x: a*x, s)
There were workarounds for this problem, but they consisted in using “default arguments” and passing hidden parameters to a lambda expression. For example:
def spam(s): a = 4 r = map(lambda x, a=a: a*x, s)
The "correct" solution of this problem for internal functions was to implicitly transfer references to all local variables into the context of the function. This approach is known as “closure” and is an important aspect of functional languages. However, this feature was not introduced in Python until version 2.2 was released.
Curiously, the map, filter, and reduce functions that originally motivated the introduction of lambda and other functionality were largely replaced with “list comprehensions” and generators. In fact, the reduce function has been removed from the list of built-in functions in Python 3.0.
Even though I did not conceive of Python as a functional language, the introduction of closures was useful in developing many other features of the language. For example, certain aspects of the new-style classes, decorators, and other modern features use closures.
Finally, even though many functional programming features have been introduced over the years, Python still lacks some functionality from “real” functional languages. For example, Python does not perform certain types of optimization (for example, tail recursion). The dynamic nature of Python made it impossible to introduce compile-time optimizations, known in functional languages as Haskell or ML.