Python程序员开发中常犯的10个错误
Python是一门简单易学的编程语言,语法简洁而清晰,并且拥有丰富和强大的类库。与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。
在平时的工作中,Python开发者很容易犯一些小错误,这些错误都很容易避免,本文总结了Python开发者最常犯的10个错误,一起来看下,不知你中枪了没有。
1.滥用表达式作为函数参数默认值
Python允许开发者指定一个默认值给函数参数,虽然这是该语言的一个特征,但当参数可变时,很容易导致混乱,例如,下面这段函数定义:
>>>deffoo(bar=[]): #barisoptionalanddefaultsto[]ifnotspecified ... bar.append("baz") #butthislinecouldbeproblematic,aswe'llsee... ... returnbar
在上面这段代码里,一旦重复调用foo()函数(没有指定一个bar参数),那么将一直返回'bar',因为没有指定参数,那么foo()每次被调用的时候,都会赋予[]。下面来看看,这样做的结果:
>>>foo() ["baz"] >>>foo() ["baz","baz"] >>>foo() ["baz","baz","baz"]
解决方案:
>>>deffoo(bar=None): ... ifbarisNone: #orifnotbar: ... bar=[] ... bar.append("baz") ... returnbar ... >>>foo() ["baz"] >>>foo() ["baz"] >>>foo() ["baz"]
2.错误地使用类变量
先看下面这个例子:
>>>classA(object): ... x=1 ... >>>classB(A): ... pass ... >>>classC(A): ... pass ... >>>printA.x,B.x,C.x 111
这样是有意义的:
>>>B.x=2 >>>printA.x,B.x,C.x 121
再来一遍:
>>>A.x=3 >>>printA.x,B.x,C.x 323
仅仅是改变了A.x,为什么C.x也跟着改变了。
在Python中,类变量都是作为字典进行内部处理的,并且遵循方法解析顺序(MRO)。在上面这段代码中,因为属性x没有在类C中发现,它会查找它的基类(在上面例子中只有A,尽管Python支持多继承)。换句话说,就是C自己没有x属性,独立于A,因此,引用C.x其实就是引用A.x。
3.为异常指定不正确的参数
假设代码中有如下代码:
>>>try: ... l=["a","b"] ... int(l[2]) ...exceptValueError,IndexError: #Tocatchbothexceptions,right? ... pass ... Traceback(mostrecentcalllast): File"<stdin>",line3,in<module> IndexError:listindexoutofrange
问题在这里,except语句并不需要这种方式来指定异常列表。然而,在Python2.x中,exceptException,e通常是用来绑定异常里的第二参数,好让其进行更进一步的检查。因此,在上面这段代码里,IndexError异常并没有被except语句捕获,异常最后被绑定到了一个名叫IndexError的参数上。
在一个异常语句里捕获多个异常的正确方法是指定第一个参数作为一个元组,该元组包含所有被捕获的异常。与此同时,使用as关键字来保证最大的可移植性,Python2和Python3都支持该语法。
>>>try: ... l=["a","b"] ... int(l[2]) ...except(ValueError,IndexError)ase: ... pass ... >>>
4.误解Python规则范围
Python的作用域解析是基于LEGB规则,分别是Local、Enclosing、Global、Built-in。实际上,这种解析方法也有一些玄机,看下面这个例子:
>>>x=10 >>>deffoo(): ... x+=1 ... printx ... >>>foo() Traceback(mostrecentcalllast): File"<stdin>",line1,in<module> File"<stdin>",line2,infoo UnboundLocalError:localvariable'x'referencedbeforeassignment
许多人会感动惊讶,当他们在工作的函数体里添加一个参数语句,会在先前工作的代码里报UnboundLocalError错误(点击这里查看更详细描述)。
在使用列表时,开发者是很容易犯这种错误的,看看下面这个例子:
>>>lst=[1,2,3] >>>deffoo1(): ... lst.append(5) #Thisworksok... ... >>>foo1() >>>lst [1,2,3,5]
>>>lst=[1,2,3] >>>deffoo2(): ... lst+=[5] #...butthisbombs! ... >>>foo2() Traceback(mostrecentcalllast): File"<stdin>",line1,in<module> File"<stdin>",line2,infoo UnboundLocalError:localvariable'lst'referencedbeforeassignment