Python 简介(6)

Lists are not Conses。 Python的列表其实比较像Lisp的可变数组,或者Java的向量(Vector)。这意味着列表的存取是O(1)的,但是与cons和cdr等价的 操作却产生了O(n)的新空间。你真的应该使用map或者for e in x:,而不是基于car/cdr的递归。注意Python里有多个空列表,而不是一个。这修正了Lisp一个常见的bug,即用户调用(nconc old new),并期待old被修改了,但是当old是nil的时候,它并没有被修改。在Python里,即使old是[ ],old.extend(new)也可以正常工作。但是这将意味着你必须用==测试列表是否为[];而不是用is,同时这也意味着,如果你把一个默认参 数的值设置为[],你最好不要修改这个值。

Python is less functional。 部分原因是Python的列表不是conses,相比于Lisp,Python使用了更多方法去改变列表的结构,并且为了强调它们的改变,它们通常返回 None值。例如像list.sort, list.reverse, 和list.remove这样的方法都是,但是Python的新版本中引入了函数式的版本,即作为一个函数而不是方法,我们现在有了sorted and reversed(但是没有removed)。

Python classes are more functional.在Lisp(CLOS)中,当你重 定义一个类C时,表示类C的对象也相应地得到修改。已经存在的C的实例和子类也因此重新指向新的类。这有时候会引起一些问题,但是在交互式的调试中,这却 是很有用的。在Python中,当你重定义一个类时,你会得到一个新的类对象,但是实例和子类还是指向旧类。这就意味着大多数时候你必须重新载入你的子 类,并且重建你的数据结构。如果你忘记了,将会引起混淆。

Python is more dynamic, does less error-checking. 在 Python中,对于未定义的函数或者域,或者传给了函数错误的参数个数,或者其他载入阶段的其他��多数问题,你都不会得到任何警告信息;你必须等到运行 时,才能得到错误信息。商业的Lisp实现将会把这些大多数问题标识为警告;简单的Lisp实现(如clisp)不会。一个演示Python危险性的地方 是,当你想写self.field = 0时,却敲入了 self.feild = 0,后者将会动态的创建一个新的域。与之相对的Lisp等价物为,(setf (feild self) 0),它将给你一个错误。另一方面,访问你一个未定义的域时,两个语言都会报告一个错误。

Don't forget self.这点更应该引起Java程序员的注意:在一个方法中,确保你写的是self.field,而不是field。这里没有隐式的作用域(scope)。通常这会引起一个运行时错误。这很令人讨厌,但是我认为过一段时间后,人们将学会不这么干。

不要忘记return.写 函数def twice(x): x+x是很诱人的,并且这不会发出任何警告或者异常信号,但是你可能真正想要的是def twice(x): return x+x。这点特别令人厌烦,因为在一个lambda表达式中,return语句是被禁止的,但是它的语义却是执行return。

注意单元素元组(tuple)。一 个元组是一个不可变的列表,并且用圆括号围起来,而不是用方括号。()是空元组,(1, 2)是一个含有两个元素的元组,但是(1)表示的是1。而一个元素的元组却要用(1,)表示,我擦!Damian Morton指出,如果你把元组看成是由逗号(,)产生的,打印时带有圆括号的数据,这样就好理解了。圆括号只是起了消除歧义的作用,在这个解释下,1, 2是含有两个元素的元组,1,是含有一个元素的元组,圆括号有时是需要的,这主要取决于元组出现的位置。例如,虽然2, + 2,是一个合法的表达式,但是更加清晰的方式是(2,) + (2,)或者(2, 2)。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/37dc91ff17a60ff90e5552368dcab356.html