云网牛站
所在位置:首页 > Linux编程 > Python程序员常犯的7个错误(新手)

Python程序员常犯的7个错误(新手)

2017-10-19 21:24:43作者:Linux编辑稿源:topspeedsnail

错误1、函数的默认参数使用不当

Python允许我们为参数指定一个默认参数值,这是很好的特性。但是当默认参数是mutable类型时,就容易忽略下面的问题:

>>> def foo(bar=[]):          # bar是一个默认参数,如果没有指定值,值为[]

...     bar.append("abc")     # 这一行也许会带来问题

...     return bar

这里一个常犯的错误是,想当然的认为使用默认参数调用foo函数时,bar的默认值总为[]。例如我们重复调用foo()(不指定参数),期望它每次返回的都是‘abc’。这是错的,实际上返回如下结果:

>>> foo()

['abc']

>>> foo()

['abc', 'abc']

>>> foo()

['abc', 'abc', 'abc']

这是因为这个默认参数只创建一次,不管你调用多少次这个函数。

可以修改为如下代码:

>>> def foo(bar=None):     # 改为非mutable类型

...     if bar is None:

...             bar = []

...     bar.append("abc")

...     return bar

... 

>>> foo()

['abc']

>>> foo()

['abc']

>>> foo()

['abc']

 

错误2、类成员变量的使用

看下面一个例子:

>>> class A(object):

...     num = 1

... 

>>> class B(A):

...     pass

... 

>>> class C(A):

...     pass

... 

>>> print A.num, B.num, C.num

1 1 1

好,没什么问题。

>>> B.num = 2

>>> print A.num, B.num, C.num

1 2 1

和预想的一样

>>> A.num = 3

>>> print A.num, B.num, C.num

3 2 3

这是怎么回事,我们只改变了A.num,为什么C.num也改了。

在Python中,类成员变量在内部是以字典形式处理的。在上面代码中,因为num在C中没有找到,它会查找它的基类。(和B不同)

 

错误3、异常处理参数不正确

>>> try:

...     abc=['a', 'b']

...     int(abc[2])

... except ValueError, IndexError:  # 试图抓取两个异常

...     pass

... 

Traceback (most recent call last):    # 只抓到一个异常,第二个异常没有抓到

File "<stdin>", line 3, in <module>

IndexError: list index out of range

上面问题在于except语句不接受list。正确的抓取多个异常应使用元组,为了兼容Python2和Python3,我们使用as关键字,如下:

>>> try:

...     abc=['a', 'b']

...     int(abc[2])

... except (ValueError, IndexError) as e:

...     pass

... 

>>> 

 

错误4、错误理解Python作用域规则

Python作用域基于LEGB规则,代表Local, Enclosing,Global, Built-in。但是在Python中会有细微的不同,看如下代码:

>>> a = 10

>>> def foo():

...     a += 1    # 同 a = a + 1

...     print a

... 

>>> foo()

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

File "<stdin>", line 2, in foo

UnboundLocalError: local variable 'a' referenced before assignment

上面问题的出现是因为在函数中对变量进行了(+=)赋值,Python会自动认为a是一个局部变量并屏蔽了外部变量。如果把上面代码改为a = 1,就没有问题,。下面看一个list的例子:

>>> l = [1, 2, 3]

>>> def foo1():

...     l.append(5)   # 这里没有问题,它使用的是全局变量l

... 

>>> foo1()

>>> l

[1, 2, 3, 5]

>>>

>>>

>>> l = [1, 2, 3]

>>> def foo2():

...     l += [5]    # 这里有问题,l被认为是局部变量(同l = l + [5])

... 

>>> foo2()

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

File "<stdin>", line 2, in foo2

UnboundLocalError: local variable 'l' referenced before assignment

 

错误5、在遍历list的同时删除其中的元素

看下面代码:

>>> is_odd = lambda x : bool(x % 2)

>>> nums = [i for i in range(10)]

>>> nums

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for i in range(len(nums)):

...     if is_odd(nums[i]):

...             del nums[i]

... 

Traceback (most recent call last):

File "<stdin>", line 2, in <module>

IndexError: list index out of range

在list或数组中边遍历边删除元素,在其他编程语言中也会出现问题。幸运的是在Python中提供了list comprehensions,实现上面功能,代码修改如下:

>>> is_odd = lambda x : bool(x % 2)

>>> nums = [i for i in range(10)]

>>> nums

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> nums[:] = [n for n in nums if not is_odd(n)]

>>> nums

[0, 2, 4, 6, 8]

 

错误6、Python的变量绑定(closure)

考虑如下代码:

>>> def create_mul():     # 生成匿名函数

...     return [lambda x : i * x for i in range(5)]

... 

>>> for m in create_mul():

...     print m(3)

希望的输出为:

0

3

6

9

12

实际的输出为:

12

12

12

12

12

出现上面问题是因为Python的延迟绑定行为,不管什么时候调用函数,i的值都是4。

解决方法如下:

>>> def create_mul():

...     return [lambda x, i = i : i * x for i in range(5)]

... 

>>> for m in create_mul():

...     print m(3)

... 

0

3

6

9

12

上面代码有点怪,这里用的是匿名函数的默认参数。

 

错误7、模块的循环依赖

假设我们有两个文件a.py和b.py,它们之间相互包含:

import b

def foo():

return b.x

print foo()

b.py:

import a

x = 1

def bar():

print a.foo()

我们先来导入a再来导入b:

>>> import a

1

>>> import b

>>>

这里没有问题,如果我们单独导入b:

>> import b

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

File "b.py", line 1, in <module>

import a

File "a.py", line 6, in <module>

print foo()

File "a.py", line 4, in foo

return b.x

AttributeError: 'module' object has no attribute 'x'

精选文章
热门文章