這些陷阱不一定是語言的缺陷,然而,這些語言的副作用,常常會使新手絆倒,甚至是有經驗的程式員也會中招。完全理解Python的一些核心行為,反而可能會使你陷入其中。
這邊文章類似於一個對Python初學者的指導,早點瞭解這些陷阱,總比在實際項目的deadline前遭遇他們要好吧 :-)這不是在批評Python語言,就像前面說的,大部分的陷阱並不是由於語言的缺陷。
1. 不一致的縮排
好吧,先來個簡單的。但是,學習其他“空格無關”的語言的新手,就會因為他們的壞習慣被Python懲罰。
解決方案:統一的縮排,全部使用空格或定位字元(tab),不要混淆使用。一個好的編輯器會很有協助。
2. 賦值、別名、對象
先學習過某些靜態語言比如Pascal和C的同學,經常會假設Python變數和賦值的工作機制和它們一樣,乍一看上去,確實一樣:
a = b = 3a = 4print a, b # 4, 3
然而,在變長對象這裡卻會出問題,那是因為Python對變長對象和定長變對象是不同的。
a = [1, 2, 3]b = aa.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 = 1a = a + 42# a is 43a = 1a += 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