您的位置:首页 > 编程语言 > Python开发

Python编程中容易出现的10个错误

2014-05-10 22:28 232 查看
Python是一个解释型、面向对象、具有动态语义的高级语言。它具有高级数据结构、动态类型绑定,支持模块化。由于Python程序员往往并非只会这一门语言,受其他语言的影响,我们在编写Python代码的时候容易出现一些错误,本文中列出了10点。

一、函数参数默认值
Python允许定义函数参数的默认值,这和C/C++是一致的。但是所不同的是,解释器只对该默认参数赋值一次。

>>> def foo(bar=[]):
...    bar.append("baz”)    
...    return bar

比如说这个foo函数,如果调用的时候自带有参数foo(a),这没什么可说的。如果用foo(),那么bar只有在一次调用无参函数foo()的时候才会执行bar=[],之后若再调用foo(),那么bar会继续使用刚才的bar,这个bar就类似于C中的static局部变量。

>>> foo()

["baz"]

>>> foo()

["baz", "baz"]

>>> foo()

["baz", "baz", "baz”]

解决办法是,在函数内部做判断。如果默认参数想定义为空的类型,用None。

>>> def foo(bar=None):

...    if bar is None:# or if not bar:

...        bar = []

...    bar.append("baz")

...    return bar

...

>>> foo()

["baz"]

>>> foo()

["baz"]

>>> foo()

["baz”]

二、类变量的继承
Python里,类变量的内部是由字典实现的。在派生类变量中,如果成员没有被定义,则会去基类中找。如果有的话的就不去看基类的了。

>>> class A(object):

...     x = 1

...

>>> class B(A):

...     pass

...

>>> class C(A):

...     pass


>>> print A.x, B.x, C.x

1 1 1

>>> B.x = 2

>>> print A.x, B.x, C.x

1 2 1

>>> A.x = 3

>>> print A.x, B.x, C.x

3 2 3

三、异常处理时参数声明
异常处理时except后面不能跟多个异常。
>>> try:

...     l = ["a", "b"]

...     int(l[2])

... except ValueError, IndexError: 

...     pass

上面这么写是不对的,第二个异常情况是捕获不到的,应该像下面这样写。

>>> try:

...     l = ["a", "b"]

...     int(l[2])

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

...     pass

四、变量的作用域
C/C++里,全局变量在函数内部是完全可见的。但是在Python里,由于是解释型语言,所以不一样了。对于一个变量,如果首次出现在赋值语句的左边,那么会被认为是一个局部变量,和外面的同名全局变量没关系。如果首次出现在赋值语句右边或者其他地方,那么就会被认为是全局变量,直接用全局变量。

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

>>> def foo1():

...     lst.append(5)   # This works ok...

...

>>> foo1()

>>> lst

[1, 2, 3, 5]

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

>>> def foo2():

...     lst += [5]      # ... but this bombs!

...

>>> foo2()

这就是为什么上面两个函数,前者是正确的,后者是错误的。

五、在遍历list的时候修改它
这个错误其实在C++使用迭代器时也会出现。即使用for循环来遍历list时,由于循环之前就确定了循环次数,修改list会导致下标的变化。

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

>>> numbers = [n for n in range(10)]

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

...     if odd(numbers[i]):

...         del numbers[i]

...

Traceback (most recent call last):

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

IndexError: list index out of range

使用下面这种高级写法,可以避免此类错误。

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

>>> numbers = [n for n in range(10)]

>>> numbers[:] = [n for n in numbers if not odd(n)]

>>> numbers

[0, 2, 4, 6, 8]

六、闭包中绑定变量
闭包中的变量的值是内函数lambda x : i * x 调用的时候才确定的。

>>> def create_multipliers():

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

>>> for multiplier in create_multipliers():

...     print multiplier(2)

对于上面的程序,不管哪一个内函数被调用时,i的值都是最后的4。因此输出会是8 8 8 8 8,而不是0 2 4 6 8。解决的办法可以利用默认参数来生成匿名函数。

>>> def create_multipliers():

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

...

>>> for multiplier in create_multipliers():

...     print multiplier(2)

七、模块之间的循环依赖
Python解释器会去设法避免重复导入模块,但是要注意顺序。

八、小心重名的模块
Python的类库非常丰富,但是要小心重名的模块。

九、不同Python版本的坑
注意Python2和Python3的区别。

十、类的析构函数
当析构函数被调用时,解释器会把变量变为None,这样有些事情就做不了了。

import foo

class Bar(object):

       ...

    def __del__(self):

        foo.cleanup(self.myhandle)

可以使用atexit.register来引入另一个函数做想做的事情。

import foo

import atexit

def cleanup(handle):

    foo.cleanup(handle)

class Bar(object):

    def __init__(self):

        ...

        atexit.register(cleanup, self.myhandle)

本文翻译自,有做增删改:
http://www.toptal.com/python/top-10-mistakes-that-python-programmers-make
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: