这里我从Python.org摘了一段对Python的简介,并我创造了两个版本:一个是用蓝色斜体显示的Python,另一个是用绿色粗体显示的Lisp。其他大部分,两个语言的共同部分,是黑色的。
Python/Lisp 是一个解释型的和编译型的, 面向对象的,高级编程语言,并且拥有动态语义。它的高级的内部数据结构,以及动态类型和动态绑定,使得它对于快速应用开发特别有吸引力,同样地,Python作为脚本或者胶水语言去链接已存在的部分,也是非常有吸引力。Python/Lisp简单、易学的语法强调的是可读性,并因此降低程序维护的成本。Python/Lisp支持模块(modules)和包(packages),这鼓励了程序的模块化和复用。Python/Lisp解释器和广泛的标准库在大多数平台上都是以源码或者二进制形式发布的,并且可以自由的散发。通常,程序员爱上Python/Lisp是因为它提供地不断增加的生产力。因为这里没有分离的(separate)编译步骤,“编辑-测试-调试”循环难以置信的快。调试Python/Lisp程序很简单:一个bug或者坏输入不会造成段错误。相反,当解释器发现一个错误,它抛出一个异常。当程序没有抓获这个异常时,解释器将打印栈轨迹。代码级别的调试允许查看局部和全局变量,求值任意表达式,设置断点,单步执行,等等。调试器是由Python/Lisp自己写的,表明了Python/Lisp的自省能力。另一方面,通常最快的调试一个程序的方法是向源码中添加一些打印语句:快速的“编辑-测试-调试”循环使得这个简单的方法特别有效。我只添加下面这句:
尽管有些人对于缩进作为块结构/括号有原始的抵制,但是大多数人最后喜欢/深深的感激 他们。想学习更多关于Python的知识,如果你是一个有经验的程序员,我推荐你去Python.org的下载页面,下载文档包,并且特别要注意Python参考手册和Python库参考。这里有各种各样的辅导材料(tutorials)和出版的书籍,但是这些参考是你真正需要的。
下面的表作为一个Lisp/Python转化的指南。红色的表项标记了这个位置中的语言,明显的比较糟糕(我自己的观点)。粗体标记了这个位置上,两个语言明显不同,但是没有一个方式明显的好于另一个。用正常字体显示的表项意味着两个语言是相似的;语法可能稍有不同,但是概念是相同的,或者非常相近。表后面是一个和一些Python的.
关键特征 Lisp 特征 Python 特征一切都是对象 是 是
对象有类型,变量没有 是 是
支持异构的(heterogenous)列表 是 (linked list and array/vector) 是 (array)
多范式语言 是:函数式,命令式,OO,Generic 是:函数式,命令式,OO
存储管理 自动垃圾收集 自动垃圾收集
包/模块 使用困难 使用简单
对象,类的自省 强大 强大
元编程的宏 强大的宏 没有宏
交互式的REPL(Read-eval-print loop) > (string-append "hello" " " "world")
"hello world" >>> ' '.join(['hello', 'world'])
'hello world'
简介、富有表达力的语言 (defun transpose (m)
(apply #'mapcar #'list m))
> (transpose '((1 2 3) (4 5 6)))
((1 4) (2 5) (3 6)) def transpose (m):
return zip(*m)
>>> transpose([[1,2,3], [4,5,6]])
[(1, 4), (2, 5), (3, 6)]
跨平台可移植性 Windows, Mac, Unix, Gnu/Linux Windows, Mac, Unix, Gnu/Linux
实现的数量 很多 一个主要的,附加一些分支(例如:Jython, Stackless)
开发模式 专有和开源 开源
效率 大约比C++慢1到2倍 大约比C++慢2到100倍
GUI, Web 等库 没有标准 GUI, Web 标准库
方法
方法分派 动态, (meth obj arg) 语法
runtime-type, multi-methods 动态, obj.meth(arg) 语法
runtime-type, single class-based
数据类型 Lisp 数据类型 Python 数据类型
Integer
Bignum
Float
Complex
String
Symbol
Hashtable/Dictionary
Function
Class
Instance
Stream
Boolean
Empty Sequence
Missing Value
Lisp List (linked)
Python List (adjustable array)
Others 42
100000000000000000
12.34
#C(1, 2)
"hello"
hello
(make-hash-table)
(lambda (x) (+ x x))
(defclass stack ...)
(make 'stack)
(open "file")
t, nil
(), #() linked list, array
nil
(1 2.0 "three")
(make-arrary 3 :adjustable t
:initial-contents '(1 2 3))
很多 (in core language) 42
100000000000000000
12.34
1 + 2J
"hello" or 'hello' ## 不可变的
'hello'
{}
lambda x: x + x
class Stack: ...
Stack()
open("file")
True, False
(), [] tuple, array
None
(1, (2.0, ("three", None)))
[1, 2.0, "three"]
很多 (in libraries)
控制结构 Lisp 控制结构 Python 控制结构
语句和表达式 一切都是表达式 区分语句和表达式
假值(False) nil是唯一的假值 False, None, 0, '', [ ], {}都是假值
函数调用 (func x y z) func(x,y,z)
条件测试 (if x y z) if x: y
else: z
条件表达式 (if x y z) y if x else z
While循环 (loop while (test) do (f)) while test(): f()
其他循环 (dotimes (i n) (f i))
(loop for x in s do (f x))
(loop for (name addr salary) in db do ...) for i in range(n): f(i)
for x in s: f(x) ## s为任意序列
for (name, addr, salary) in db: ...
赋值 (setq x y)
(psetq x 1 y 2)
(rotatef x y)
(setf (slot x) y)
(values 1 2 3) 在栈上
(multiple-value-setq (x y) (values 1 2)) x = y
x, y = 1, 2
x, y = y, x
x.slot = y
(1, 2, 3) 在堆中
x, y = 1, 2
异常 (assert (/= denom 0))
(unwind-protect (attempt) (recovery))
(catch 'ball ... (throw 'ball)) assert denom != 0, "denom != 0"
try: attempt()
finally: recovery()
try: ...; raise 'ball'
except 'ball': ...
其他控制结构 case, etypecase, cond, with-open-file, etc. 扩展的with语句
没有其他控制结构
词法结构 Lisp 词法结构 Python 词法结构
注释 ;; 分号直到行尾 ## 井号直到行尾
界定符(Delimiters) 用括号来界定表达式
(defun fact (n)
(if (<= n 1) 1
(* n (fact (- n 1))))) 用缩进来界定语句
def fact (n):
if n <= 1: return 1
else: return n * fact(n — 1)
高阶函数 Lisp 高阶函数 Python 高阶函数
应用函数
执行一个表达式
执行一个语句
加载文件 (apply fn args)
(eval '(+ 2 2)) => 4
(eval '(dolist (x list) (f x)))
(load "file.lisp") or (require 'file) apply(fn, args) or fn(*args)
eval("2+2") => 4
exec("for x in list: f(x)")
execfile("file.py") or import file
序列函数 (mapcar length '("one" (2 3))) => (3 2)
(reduce #'+ numbers)
(every #'oddp '(1 3 5)) => T
(some #'oddp '(1 2 3)) => 1
(remove-if-not #'evenp numbers)
(reduce #'min numbers) map(len, ["one", [2, 3]]) => [3, 2]
or [len(x) for x in ["one", [2, 3]]]
reduce(operator.add, numbers)
all(x%2 for x in [1,3,5]) => True
any(x%2 for x in [1,2,3]) => True
filter(lambda x: x%2 == 0, numbers)
or [x for x in numbers if x%2 == 0]
min(numbers)
其他高阶函数 count-if 等
:test, :key 等关键字参数 没有其他内置的高阶函数
map/reduce/filter函数没有关键字参数
Close over read-only var
Close over writable var (lambda (x) (f x y))
(lambda (x) (incf y x)) lambda x: f(x, y)
Can't be done; use objects
参数列表 Lisp 参数列表 Python 参数列表
可选参数
变长参数
未确定的关键字参数
调用约定 (defun f (&optional (arg val) ...)
(defun f (&rest arg) ...)
(defun f (&allow-other-keys &rest arg) ...)
只有明确声明时,才可以用关键词方式调用:
(defun f (&key x y) ...)
(f :y 1 :x 2) def f (arg=val): ...
def f (*arg): ...
def f (**arg): ...
用关键字方式调用任何函数:
def f (x,y): ...
f(y=1, x=2)
效率 Lisp 效率问题 Python 效率问题
编译
函数引用解析
声明 编译到本机代码
大多数“函数/方法”的查找很快
为了效率可以进行声明 编译到字节码
大多数“函数/方法”的查找比较慢
没有声明
特征 Lisp 特征和函数 Python 特征和函数
引用(Quotation) 引用整个列表结构:
'hello
'(this is a test)
'(hello world (+ 2 2)) 引用单个的字符串或者.split():
'hello'
'this is a test'.split()
['hello', 'world', [2, "+", 2]]
自省(Introspectible)文档字符串 (defun f (x)
"compute f value"
...)
> (documentation 'f 'function)
"compute f value" def f(x):
"compute f value"
...
>>> f.__doc__
"compute f value"
列表访问 通过函数:
(first list)
(setf (elt list n) val)
(first (last list))
(subseq list start end)
(subseq list start) 通过语法:
list[0]
list[n] = val
list[-1]
list[start:end]
list[start:]
哈希表访问 通过函数:
(setq h (make-hash-table))
(setf (gethash "one" h) 1.0)
(gethash "one" h)
(let ((h (make-hash-table)))
(setf (gethash "one" h) 1)
(setf (gethash "two" h) 2)
h) 通过语法:
h = {}
h["one"] = 1.0
h["one"] or h.get("one")
h = {"one": 1, "two": 2}
列表上的操作 (cons x y)
(car x)
(cdr x)
(equal x y)
(eq x y)
nil
(length seq)
(vector 1 2 3) [x] + y but O(n); also y.append(x)
x[0]
x[1:] but O(n)
x == y
x is y
() or [ ]
len(seq)
(1, 2, 3)
数组上的操作 (make-array 10 :initial-element 42)
(aref x i)
(incf (aref x i))
(setf (aref x i) 0)
(length x)
#(10 20 30) 如果大小不变的话 10 * [42]
x[i]
x[i] += 1
x[i] = 0
len(x)
[10, 20, 30]