[置顶] 十个Python陷阱(13)

这些陷阱不一定是语言的缺陷,然而,这些语言的副作用,常常会使新手绊倒,甚至是有经验的程序员也会中招。完全理解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


原文地址:https://www.cnblogs.com/javawebsoa/p/3037457.html