PEAK:基于类型的分派

Python 是一种相当高级的语言,但是我们为什么只是局限于这一级别的抽象呢?利用 PEAK(Python Enterprise Application Kit),我们可以实现更高级的抽象。

PEAK 是 TransWarp 的后继者,是一个用 Python 开发的用于软件自动化的实验性工具包,是一个用于快速开发和重用应用程序组件的 Python 框架。PEAK 为您提供一个组件架构、组件基础设施,以及各种用于构建应用程序的通用组件和组件框架。

介绍 PEAK 最简单的方法是作为“Phillip J. Eby 最近研究的最疯狂的思想”。不管语气如何,我对此总是有些调侃。尽管 PEAK 已经吸引了像其他中等规模的 Free Software Python 项目一样多的贡献者,但是实际上 PEAK 的方向是由不断变革的目标和最初创建者的兴趣所驱动的。

PEAK 随着这种不断变化的兴趣而变化的一个必然结果是,它在可预见的未来一段时间内将可能有点是“实验性的”。这就是说,我们不用太过担心这个问题 —— 我所尝试过的每个 PEAK 版本都很稳定,而且都提供了一些特性。另外,您现在可以获得 PEAK 最新快照的一个自动更新的 tarball,其中还提供了一个非常友好的 distutils 安装脚本。

从我最后一次介绍 PEAK 到现在的一年时间中(请参阅 可爱的 Python: Python Enterprise Application Kit),PEAK 中所引入的最有趣的一种思想是通用函数(generic function)本文将重点介绍这种功能,虽然这不过是整个 PEAK 的冰山一角。而且,这种思想可以与我的多分派模块(multimethods)很自然地结合起来,我很高兴看到 PEAK 可以对分派风格进行扩展。

在开始继续讨论通用函数之前,我们有必要先来看一下 PEAK 的 Wiki 主页(您可以查看这个页面的最新状态,请参阅 参考资料 中的链接)上给出的一个 PEAK 的组件图。

图 1. PEAK 的组件

PEAK:基于类型的分派_第1张图片

断言分派

一点简短的提示:术语 “predicate dispatch”比“predicative”使用得更多,尽管后者从文法上来说更加适合。如果我们要在 Web 或者库函数中进行搜索,可以尝试一下这个简短的拼写方法。

基于类型的分派

阅读过我之前编写的有关 Gnosis Utilities 模块 gnosis.magic.multimethods 的文章的读者对于多分派都有一个基本的印象了。现在我们回忆一下,大部分 OOP 编程都是单一的分派;这就是说,只有一个指定的对象用来确定要走哪条代码路径。在一个诸如 foo.doIt(other,args,here) 之类的调用中,点号之前的参数的类 —— 也就是 Foo —— 确定了要运行哪些代码;other 等参数的类型可能会在 Foo.doIt() 的 if 语句中进行测试,但是不会直接影响代码的分派。

从概念上来说,一种更加通用的技术是让函数/方法的所有参数都以相同的度量来确定自己的专有程度。在多分派的系统中,诸如 doIt() 之类的通用函数可以专门用来处理各种专用的类型签名。gnosis.magic.multimethods() API 中,这可能会类似于清单 1 所示:

清单 1. multimethods.py 中对类型进行多分派

1
2
3
4
doIt.add_rule((Foo1, Other2, int), func1)
doIt.add_rule((Foo2, Other1, str), func2)
doIt.add_rule((Foo1, Other1, float), func3)
doIt(foo, other, args)  # 'foo' is just one co-equal specializer


PEAK 的 dispatch 模块也有一个基于类型的分派器,但是目前尚微不足道,因为它只能处理单一分派 —— dispatch.on() 封装程序除了基于普通 Python 类的分派之外还做不了多少事情。尽管如此,看到 PEAK 的基于类型的分派仍然让我们对完整断言分派的语法兴奋不已。注意这些例子都利用了 Python 2.4 中新的 decorator 语法,用于修改所定义的函数或方法。可以在早期版本的 Python 中使用 PEAK 的通用函数,但是其语法并不美观(如清单 2 所示):

清单 2. PEAK 分派包中对类型进行单一分派

1
2
3
4
5
6
7
8
9
10
11
12
import dispatch
@dispatch.on('foo')
def doIt(foo, other, args):
     "Base generic function of 'doIt()'"
@doIt.when(int)
def doIt(foo, other, args):
     print "foo is an int |", other, args
@doIt.when(str)
def doIt(foo, other, args):
     print "foo is a str |", other, args
doIt( 1, 'this','that')  # -> foo is an int | this that
doIt('x','this','that')  # -> foo is a str | this that


对于新的类型来说,的确可以添加 dispatch.on() 通用函数签名,而不用修改以前的代码。例如,我可以向前面的代码中添加 @doIt.when(float) 或 @doIt.when(MyClass)如果需要,以后的调用就可以利用它。但是即使不用 PEAK dispatch 包,也有很多方法可以实现同样的功能。

商务合作,请加微信:Fun-lying


640?wx_fmt=jpeg


640?wx_fmt=png 我怎么这么好看

你可能感兴趣的:(PEAK:基于类型的分派)