可爱的 Python: Python 中的函数编程
2007-03-29 12:05:55 来源:WEB开发网这个项目太小,以至于没有什么可能出错。但我们的目的可能嵌在要同时实现许多其它目的的代码中。用 "more stuff" 注释的那些部分是副作用可能导致错误发生的地方。在这些地方中的任何一处,变量 xs 、 ys 、 bigmuls 、 x 、 y 有可能获得假设节略代码中的意外值。而且,在执行完这一段代码后,所有变量都可能具有稍后代码可能需要也可能不需要的一些值。很明显,可以使用函数/实例形式的封装和有关作用域的考虑来防止出现这种类型的错误。而且,您总是可以在执行完变量后 del 它们。但在实际中,这些指出类型的错误非常普遍。
目标的函数方法完全消除了这些副作用错误。以下是可能的一段代码:
清单 8. “打印大乘积”的函数 Python 代码
bigmuls =
lambda
xs,ys: filter(
lambda
(x,y):x*y > 25, combine(xs,ys))
combine =
lambda
xs,ys: map(None, xs*len(ys), dupelms(ys,len(xs)))
dupelms =
lambda
lst,n: reduce(
lambda
s,t:s+t, map(
lambda
l,n=n: [l]*n, lst))
print
bigmuls((1,2,3,4),(10,15,3,22))
在示例中,我们将匿名 ( lambda ) 函数对象与名称进行绑定,但这不是一定必要的。我们可以只嵌套定义。这样做是出于可读性目的;但也是因为 combine() 是一种随处可得的很好实用程序函数(从两个输入列表中产生所有元素对的列表)。随后的 dupelms() 主要只是帮助 combine() 发挥作用的一种方法。即使这一函数示例比命令示例更冗长,但一旦考虑到实用程序函数可以重用,那么 bigmuls() 中的新代码本身可能比命令版本中的代码数量还要少一些。
这种函数示例真正的优势在于绝对不会有变量更改其中的任何值。稍后的代码中没有 可能的不曾预料到的副作用(较早的代码中也不会有)。很明显,它本身没有副作用并不能保证代码 正确,但即使这样,这也是个优点。不过请注意,Python(与许多函数语言不同) 不能 防止名称 bigmuls 、 combine 和 dupelms 的重新绑定。如果 combine() 在程序的稍后部分中开始有其它意义,则所有努力都前功尽弃。您可以逐步建立一个 Singleton 类来包含这种类型的不可变绑定(例如 s.bigmuls 等);但本专栏并不涉及这一内容。
特别值得注意的一个问题是我们的特定目的是对 Python 2 中的新特性进行定制。最好的(也是函数的)技术既不是上面提供的命令示例,也不是函数实例,而是:
清单 9. "bigmuls" 的列表内涵 Python 代码
print
[(x,y)
for
x
in
(1,2,3,4)
for
y
in
(10,15,3,22)
if
x*y > 25]
结束语
我已介绍了使用函数等价物替换每个 Python 流控制构造所使用的方法(在过程中消除了副作用)。对特定程序进行有效转换将带来一些额外的考虑,但我们已经知道内置函数是常规而完整的。在稍后的专栏中,我们将考虑一些更高级的函数编程技术;希望能够探索函数风格的更多利弊。
更多精彩
赞助商链接