关于Python
Python是一种解释性、面向对象并具有动态语义的高级程序语言。它内建了高级的数据结构,结合了动态类型和动态绑定的优点,这使得它在快速应用开发中非常有吸引力,并且可作为脚本或胶水语言来连接现有的组件或服务。Python支持模块和包,从而鼓励了程序的模块化和代码重用。
关于这篇文章
Python简单易学的语法可能会使Python开发者–尤其是那些编程的初学者–忽视了它的一些微妙的地方并低估了这门语言的能力。
有鉴于此,本文列出了一个“10强”名单,枚举了甚至是高级Python开发人员有时也难以捕捉的错误。
常见错误 #1: 滥用表达式作为函数参数的默认值
Python允许为函数的参数提供默认的可选值。尽管这是语言的一大特色,但是它可能会导致一些易变默认值的混乱。例如,看一下这个Python函数的定义:
- >>> def foo(bar=[]): # bar is optional and defaults to [] if not specified
- ... bar.append("baz") # but this line could be problematic, as we'll see...
- ... return bar
一个常见的错误是认为在函数每次不提供可选参数调用时可选参数将设置为默认指定值。在上面的代码中,例如,人们可能会希望反复(即不明确指定bar参数)地调用foo()时总返回'baz',由于每次foo()调用时都假定(不设定bar参数)bar被设置为[](即一个空列表)。
但是让我们看一下这样做时究竟会发生什么:
- >>> foo()
- ["baz"]>>> foo()
- ["baz", "baz"]>>> foo()
- ["baz", "baz", "baz"]
耶?为什么每次foo()调用时都要把默认值"baz"追加到现有列表中而不是创建一个新的列表呢?
答案是函数参数的默认值只会评估使用一次—在函数定义的时候。因此,bar参数在初始化时为其默认值(即一个空列表),即foo()首次定义的时候,但当调用foo()时(即,不指定bar参数时)将继续使用bar原本已经初始化的参数。
下面是一个常见的解决方法:
- >>> def foo(bar=None):
- ... if bar is None: # or if not bar:
- ... bar = []
- ... bar.append("baz")
- ... return bar
- ...
- >>> foo()
- ["baz"]
- >>> foo()
- ["baz"]
- >>> foo()
- ["baz"]
常见错误 #2: 错误地使用类变量
考虑一下下面的例子:
- >>> 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
什么 $%#!&?? 我们只改了A.x,为什么C.x也改了?
在Python中,类变量在内部当做字典来处理,其遵循常被引用的方法解析顺序(MRO)。所以在上面的代码中,由于class
C中的x属性没有找到,它会向上找它的基类(尽管Python支持多重继承,但上面的例子中只有A)。换句话说,class
C中没有它自己的x属性,其独立于A。因此,C.x事实上是A.x的引用。