The History of Python

2009年5月1日星期五

Python函数编程特性的起源

英文原文链接:http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html


原文作者:Guido van Rossum


不管别人怎么说的想的,我是从来也没想到Python会被函数式编程语言影响如此之深。我对C和Algol 68这类命令式编程语言更为熟悉,而且即使我设定函数为一类公民对象,我也没有将Python看做是函数式编程语言。然而从一开始,就清楚的发现用户希望利用list和函数做更多的事情。


一个对list的常见操作是对其每一个元素调用某个函数并将结果生成一个新的list,例如:



def square(x):
return x*x

vals = [1, 2, 3, 4]
newvals = []
for v in vals:
newvals.append(square(v))

Lisp和Scheme等函数式编程语言会提供内置函数来实现类似操作。因此熟悉这些语言的早期用户会自己动手在Python中实现类似功能的函数,例如:



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)

上述代码的一点小问题是许多人不喜欢应用到列元素的操作被分开定义为一个的单独函数。Lisp等语言允许在进行映射函数调用时直接“当场”定义函数。例如,在Scheme语言中你可以利用lambda在一条语句中创建匿名函数并执行映射操作,像下面这样:



(map (lambda (x) (* x x)) '(1 2 3 4))

虽然Python中函数是一类公民对象,当时并没有任何创建类似匿名函数的机制。


到1993年底,用户已经提出了各种创建匿名函数的思路,和各种list操纵函数如map()、filter()和reduce()。例如,Mark Lutz(《Programming Python》的作者)贴过一段利用exec来产生函数的函数代码:



def genfunc(args, expr):
exec('def f(' + args + '): return ' + expr)
return eval('f')

# Sample usage
vals = [1, 2, 3, 4]
newvals = map(genfunc('x', 'x*x'), vals)

Tim Peters又跟进提出了一个语法上略微简化的方案,允许用户这样写代码:



vals = [1, 2, 3, 4]
newvals = map(func('x: x*x'), vals)


这些都表明了对这一功能确有实际需求。然而当时利用exec手工将包含代码的字符串转换为匿名函数过于“儿戏”。于是1994年1月,map()、filter()和reduce()被添加到标准库。另外,lambda操作符也被语法上直观的引入以创建匿名函数(或称匿名表达式)。例如:



vals = [1, 2, 3, 4]
newvals = map(lambda x:x*x, vals)

这些是早期的重要贡献代码。不幸的是我想不起作者是谁了,而SVN的日志也没有记录。如果是你的话,请留言!


我从来也没有喜欢过“lambda”这个术语,但是又找不到更合适的替代者,于是也只好用了这个。毕竟lambda是当时无名代码贡献者的选择,那时大的改动比现在需要的讨论要少的多,讨论少的影响有好有坏


Lambda最初只用来当做定义匿名函数的语法工具。然而选择lambda这个词带来了许多意外后果。例如熟悉函数式编程语言的用户希望Python中的lambda能和其它语言相似。结果他们发现Python的实现缺少对高级特性的支持。例如一个小问题是lambda表达式无法引用上下文中变量。于是下面代码中map()函数将会出错,提示lambda函数中引用了未定义的变量“a”。



def spam(s):
a = 4
r = map(lambda x: a*x, s)

可以用下面代码来凑活着解决这个问题,不过涉及设置缺省参数和传递隐含参数很不直观:



def spam(s):
a = 4
r = map(lambda x, a=a: a*x, s)

这个问题的“标准”答案是对所有被函数引用的相关上下文中局部变量,内部函数隐含支持对这些变量的引用。这也就是“闭包(closure)”,函数式编程语言中的一个关键特性。然后Python直到2.2版本才引入对闭包的支持(python2.1版本也可以通过“from the future”方式使用)。


有意思的是,map、filter和recude函数,他们是最初引入lambda和其它函数式编程语言特征的源动力,自身却很大程度上被list comprehensions和generator expressions盖过了风头。以至于在Python3.0中reduce函数已经从内置函数列表中移除。(不必担心lambda、map和filer,他们已经被保留了:-)


要提到的是,即使我还是没有把Python当做函数式编程语言的情况下,闭包的引入却成功的用于开发其它高级语言特性。例如new-style class的某些方面,decorator和依赖它的其它现代特性。


最后,即使一部分函数式编程语言特征已引入多年,Python仍然缺乏一些“真正”函数式编程语言的特性。例如Python不支持特定情况的优化(例如尾递归)。总起来说,因为Python的深度动态本质,无法做到Haskell或者ML这类函数式编程语言的编译时优化。这是好事

没有评论: