[置顶] 十个Python陷阱(1-3)
这些陷阱不一定是语言的缺陷,然而,这些语言的副作用,常常会使新手绊倒,甚至是有经验的程序员也会中招。完全理解Python的一些核心行为,反而可能会使你陷入其中。
这边文章类似于一个对Python初学者的指导,早点了解这些陷阱,总比在实际项目的deadline前遭遇他们要好吧 :-)这不是在批评Python语言,就像前面说的,大部分的陷阱并不是由于语言的缺陷。
1. 不一致的缩进
好吧,先来个简单的。但是,学习其他“空格无关”的语言的新手,就会因为他们的坏习惯被Python惩罚。
解决方法:统一的缩进,全部使用空格或制表符(tab),不要混淆使用。一个好的编辑器会很有帮助。
2. 赋值、别名、对象
先学习过某些静态语言比如Pascal和C的同学,经常会假设Python变量和赋值的工作机制和它们一样,乍一看上去,确实一样:
a = b = 3 a = 4 print a, b # 4, 3
然而,在变长对象这里却会出问题,那是因为Python对变长对象和定长变对象是不同的。
a = [1, 2, 3] b = a a.append(4) print b # b is now [1, 2, 3, 4] as well
这是怎么回事?一个声明语句a = [1, 2, 3]做了两件事:1. 创建一个对象(一个list)并赋值为[1, 2, 3];2. 在本地命名空间中将a绑定到改变量上。b = a 将b绑定到相同的list(已经被a引用的)上。一旦你意识到这个,理解a.append(4)的行为就简单多了,它改变了被a和b引用的list的值。
关于定长对象和变长对象在赋值时表现不同的说法事实上是不对的。当a = 3 b = a,这时a和b都引用了同一个对象——一个值为3的整数对象,但是,因为整数对象是不可变的,你并不会陷入到陷阱中。
解决方法:使用拷贝方法,切片操作符等,Python从不隐式拷贝。Read this.
3. +=操作符
诸如C之类的语言,+=是一个简化表达式的运算符,例如:
x += 42;
是下面的表达式的简化:
x = x + 42;
所以,你可能认为在Python中也是一样的。当然,初看上去确实一样:
a = 1 a = a + 42 # a is 43 a = 1 a += 42 # a is 43
然而,对于变长对象,x += y 跟 x = x + y不完全相同。考虑list:
>>> z = [1, 2, 3] >>> id(z) 24213240 >>> z += [4] >>> id(z) 24213240 >>> z = z + [5] >>> id(z) 24226184
x += y 就地改变了list的值,而x = x + y创建了一个新的list并重新将x绑定上去。一个细微的差别可能导致难以追踪的BUG。
不仅仅是这些,当混合使用定长对象和变长对象的时候,你会有更加惊奇的发现:
>>> t = ([],) >>> t[0] += [2, 3] Traceback (most recent call last): File "<input>", line 1, in ? TypeError: object doesn't support item assignment >>> t ([2, 3],)
明显的,元组不支持对其中元素的赋值——但是在对他使用+=后,元组里的list确实改变了!原因依然是+=就地改变list的值。但是元组的赋值不被允许,当异发生时,元组中的list已经被就地改变了。
这就是一个我个人觉得非常致命的陷阱。
解决方法:干脆避免使用+=,或者仅仅在整数时使用它。:-)
原文:http://zephyrfalcon.org/labs/python_pitfalls.html