注意特定的异常 小心: 当key不存在时,dict[key]会抛出KeyError; lisp哈希表的用户则期望得到nil。你应该捕获这个异常或者用key in dict测试。
Python是Lisp-1的。 我的意思是Python只有一个命名空间,里面包含了变量和函数,就像scheme一样,而不是想Common Lisp那样,有两个命名空间。例如:
1 2 3
def f(list, len): return list((len, len(list))) ## bad Python (define (f list length) (list length (length list))) ;; bad Scheme (defun f (list length) (list length (length list))) ;; legal Common Lisp
对于域和方法也是一样:你不能提供一个和域名相同的方法名:
1 2 3
class C: def f(self): return self.f ## bad Python ...
Python字符串不同于Lisp的符号(symbol)。Python通过把字符串内化到模块或类的哈希表中,然后进行符号查找。也就是说,当你写obj.slot时,Python在运行阶段会去obj类的哈希表中查找字符串"slot"。Python也会内化一些用户代码中的字符串,例如,当你写x = "str"时。但是Python并不内化那些看起来不像变量的字符串,例如x = "a str"(感谢Brian Spilsbur指出这点)。
Python没有宏(macro)。 Python可以访问一个程序的抽象语法树,但是这不是适合“心脏不好”的人。从积极的方面来看,该模块容易理解,并且在5分钟内,我用5行代码就可以得到:
1 2 3 4 5
>>> parse("2 + 2") ['eval_input', ['testlist', ['test', ['and_test', ['not_test', ['comparison', ['expr', ['xor_expr', ['and_expr', ['shift_expr', ['arith_expr', ['term', ['factor', ['power', ['atom', [2, '2']]]]], [14, '+'], ['term', ['factor', ['power', ['atom', [2, '2']]]]]]]]]]]]]]], [4, ''], [0, '']]
这令我相当失望,同样的表达式在Lisp中的解析结果是(+ 2 2)。看来,只有真正的专家才会想去操纵Python的解析树,相 反,Lisp的解析树对任何人来说都是简单可用。我们任然可以在Python中,通过连接字符串,来创建一些类似于宏的东西,但是它不能和其他语言集成, 所以在实践中不这样做。在Lisp中,两个使用宏的主要目的是:新的控制结构和定制针对特定问题的语言。前者没有在Python中实现。后者可以通过在 Python中,用适合特定问题的数据格式来做到:下面我在Python中定义了一个上下文无关语法,分别通过1)组合字典的内置语法,2)解析字符串的 预处理过程完成的。第一种方式和Lisp的宏一样优雅。但是对于复杂的任务,例如为逻辑编程语言写一个编译器这样的事,在Lisp中很容易,但是在 Python将很困难。
比较Lisp和Python程序我从《Paradigms of Artificial Intelligence Programming》一书中取了一个简单的随机句子生产器程序,并把它翻译成Python。结论:简介性相当;Python因为grammar[phrase]比 (rule-rhs (assoc phrase *grammar*))简单,而获得一分,但是Lisp因为'(NP VP)比['NP', 'VP']更简介而扳平比分。Python程序很可能比较低效,但是这不是我们关注的点。两个语言看起来都很适合这样的程序。调整浏览器窗口到合适的宽度以便阅读代码。
Lisp程序 simple.lisp Python程序 simple.py(defparameter *grammar* '((sentence -> (noun-phrase verb-phrase)) (noun-phrase -> (Article Noun)) (verb-phrase -> (Verb noun-phrase)) (Article -> the a) (Noun -> man ball woman table) (Verb -> hit took saw liked)) "A grammar for a trivial subset of English.") (defun generate (phrase) "Generate a random sentence or phrase" (cond ((listp phrase) (mappend #'generate phrase)) ((rewrites phrase) (generate (random-elt (rewrites phrase)))) (t (list phrase)))) (defun generate-tree (phrase) "Generate a random sentence or phrase, with a complete parse tree." (cond ((listp phrase) (mapcar #'generate-tree phrase)) ((rewrites phrase) (cons phrase (generate-tree (random-elt (rewrites phrase))))) (t (list phrase)))) (defun mappend (fn list) "Append the results of calling fn on each element of list. Like mapcon, but uses append instead of nconc." (apply #'append (mapcar fn list))) (defun rule-rhs (rule) "The right hand side of a rule." (rest (rest rule))) (defun rewrites (category) "Return a list of the possible rewrites for this category." (rule-rhs (assoc category *grammar*)))