在上面的代码中,我已经用一些不同的方法声明了许多适配器。在一些情况中,代码将一个接口转换到另一个接口;在其他情况中,类型本身直接适配到另一个接口。我希望您能注意到关于代码的一些方面:(1)没有创建任何从 list 或 tuple 到 ILisp 接口的适配器;(2)没有为 int 数字类型显式声明适配器;(3)就此而言,没有声明直接由 dict 到 ILisp 的适配器。下面是代码将如何适配( adapt() )各种 Python 对象:
test_lispy.py 对象序列化 from lispy import * from sys import stdout, stderr toLisp = lambda o: adapt(o, ILisp) class Foo: def __init__(self): self.a, self.b, self.c = 'a','b','c' tests = [ "foo bar", {17:2, 33:4, 'biz':'baz'}, ["bar", ('f','o','o')], 1.23, (1L, 2, 3, 4+4j), Foo(), True, ] for test in tests: stdout.write(toLisp(test)+' ')
运行时,我们得到:
test_lispy.py 序列化结果 $ python2.3 test_lispy.py '(foo bar) (MAP (17 2) ('(biz) '(baz)) (33 4) ) (MAP (0 '(bar)) (1 (MAP (0 '(f)) (1 '(o)) (2 '(o)) )) ) (FLOAT 1.23) (MAP (0 (LONG 1)) (1 2) (2 3) (3 (COMPLEX (4+4j))) ) (CLASS '(Foo) (MAP ('(a) '(a)) ('(c) '(c)) ('(b) '(b)) )) (BOOL True)
对我们的输出进行一些解释将会有所帮助。第一行比较简单,我们定义了一个直接从字符串到 ILisp 的适配器,对 adapt("foo bar", ILisp) 的调用只是返回了 lambda 函数的结果。下一行只是有一点复杂。没有直接从 dict 到 ILisp 的适配器;但我们不必使用任何适配器就可以让 dict 去适配 IMap (我们声明了足够多),而且我们有从 IMap 到 ILisp 的适配器。类似的,对于后面的列表和元组,我们可以使 ILisp 适配 ISeq ,使 ISeq 适配 IMap ,并使 IMap 适配 ILisp 。PyProtocols 会指出要采取的适配路径,所有这些不可思议的过程都在幕后完成。一个旧风格的实例所经历的过程与字符串或者支持 IMap 的对象相同,我们有一个直接到 ILisp 的适配。
不过,等一下。在我们的 dict 和 tuple 对象中用到的所有的整数是怎么处理的呢? long 、 complex、 float 和 bool 类型的数字有显式的适配器,不过 int 一个都没有。这里的技巧在于, int 对象已经拥有一个 .__repr__() 方法;通过将隐式支持声明为 ILisp 接口的一部分,我们可以巧妙地使用对象已有的 .__repr__() 方法作为对 ILisp 接口的支持。实际上,作为一个内置的类型,整数用不加任何修饰的阿拉伯数字表示,而不使用大写的类型初始器(比如 LONG )。
(编辑:aniston)
|