说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

Python开发者最常犯的10个错误

HTML文档下载 WORD文档下载 PDF文档下载
Python是一门简单易学的编程语言,语法简洁而清晰,并且拥有丰富和强大的类库。在日常开发中,开发者很容犯一些低级的错误,本文总结了开发者最容易犯的10个错误。

Python是一门简单易学的编程语言,语法简洁而清晰,并且拥有丰富和强大的类库。与其它大多数程序设计语言使用大括号不一样 ,它使用缩进来定义语句块。

在平时的工作中,Python开发者很容易犯一些小错误,这些错误都很容易避免,本文总结了Python开发者最常犯的10个错误,一起来看下,不知你中枪了没有。


1.滥用表达式作为函数参数默认值

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

在上面这段代码里,一旦重复调用foo()函数(没有指定一个bar参数),那么将一直返回'bar',因为没有指定参数,那么foo()每次被调用的时候,都会赋予[]。下面来看看,这样做的结果:

>>> foo()["baz"]>>> foo()["baz", "baz"]>>> foo()["baz", "baz", "baz"]
解决方案:

>>> 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.x1 1 1
这样是有意义的:

>>> B.x = 2>>> print A.x, B.x, C.x1 2 1
再来一遍:

>>> A.x = 3>>> print A.x, B.x, C.x3 2 3
仅仅是改变了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])... except ValueError, IndexError:  # To catch both exceptions, right?...     pass...Traceback (most recent call last):  File "<stdin>", line 3, in <module>IndexError: list index out of range

问题在这里,except语句并不需要这种方式来指定异常列表。然而,在Python 2.x中,except Exception,e通常是用来绑定异常里的 第二参数,好让其进行更进一步的检查。因此,在上面这段代码里,IndexError异常并没有被except语句捕获,异常最后被绑定 到了一个名叫IndexError的参数上。

在一个异常语句里捕获多个异常的正确方法是指定第一个参数作为一个元组,该元组包含所有被捕获的异常。与此同时,使用as关键字来保证最大的可移植性,Python 2和Python 3都支持该语法。

>>> try:...     l = ["a", "b"]...     int(l[2])... except (ValueError, IndexError) as e:  ...     pass...>>>
4.误解Python规则范围

Python的作用域解析是基于LEGB规则,分别是Local、Enclosing、Global、Built-in。实际上,这种解析方法也有一些玄机,看下面这个例子:

>>> x = 10>>> def foo():...     x += 1...     print x...>>> foo()Traceback (most recent call last):  File "<stdin>", line 1, in <module>  File "<stdin>", line 2, in fooUnboundLocalError: local variable 'x' referenced before assignment

许多人会感动惊讶,当他们在工作的函数体里添加一个参数语句,会在先前工作的代码里报UnboundLocalError错误( 点击这里查看更详细描述)。

在使用列表时,开发者是很容易犯这种错误的,看看下面这个例子:

>>> 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()Traceback (most recent call last):  File "<stdin>", line 1, in <module>  File "<stdin>", line 2, in fooUnboundLocalError: local variable 'lst' referenced before assignment
为什么foo2失败而foo1运行正常?

答案与前面那个例子是一样的,但又有一些微妙之处。foo1没有赋值给lst,而foo2赋值了。lst += [5]实际上就是lst = lst + [5],试图给lst赋值(因此,假设Python是在局部作用域里)。然而,我们正在寻找指定给lst的值是基于lst本身,其实尚未确定。

5.修改遍历列表

下面这段代码很明显是错误的:

>>> 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]  # BAD: Deleting item from a list while iterating over it...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)]  # ahh, the beauty of it all>>> numbers[0, 2, 4, 6, 8]
6.如何在闭包中绑定变量

看下面这个例子:

>>> def create_multipliers():...     return [lambda x : i * x for i in range(5)]>>> for multiplier in create_multipliers():...     print multiplier(2)...
你期望的结果是:

<code>02468</code>
实际上:

<code>88888</code>
是不是非常吃惊!出现这种情况主要是因为Python的后期绑定行为,该变量在闭包中使用的同时,内部函数又在调用它。

解决方案:

>>> def create_multipliers():...     return [lambda x, i=i : i * x for i in range(5)]...>>> for multiplier in create_multipliers():...     print multiplier(2)...02468
7.创建循环模块依赖关系

假设有两个文件,a.py和b.py,然后各自导入,如下:

在a.py中:

import bdef f():    return b.x	print f()
在b.py中:

import ax = 1def g():    print a.f()
首先,让我们试着导入a.py:

<code>>>> import a1</code>

可以很好地工作,也许你会感到惊讶。毕竟,我们确实在这里做了一个循环导入,难道不应该有点问题吗?

仅仅存在一个循环导入并不是Python本身问题,如果一个模块被导入,Python就不会试图重新导入。根据这一点,每个模块在试图访问函数或变量时,可能会在运行时遇到些问题。

当我们试图导入b.py会发生什么(先前没有导入a.py):

>>> import bTraceback (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 f()  	  File "a.py", line 4, in f	return b.xAttributeError: 'module' object has no attribute 'x'

出错了,这里的问题是,在导入b.py的过程中还要试图导入a.py,这样就要调用f(),并且试图访问b.x。但是b.x并未被定义。

可以这样解决,仅仅修改b.py导入到a.py中的g()函数:

x = 1def g():    import a	# This will be evaluated only when g() is called    print a.f()
无论何时导入,一切都可以正常运行:

>>> import b>>> b.g()1	# Printed a first time since module 'a' calls 'print f()' at the end1	# Printed a second time, this one is our call to 'g'
8.与Python标准库模块名称冲突

Python拥有非常丰富的模块库,并且支持“开箱即用”。因此,如果不刻意避免,很容易发生命名冲突事件。例如,在你的代码中可能有一个email.py的模块,由于名称一致,它很有可能与Python自带的标准库模块发生冲突。

9.未按规定处理Python2.x和Python3.x之间的区别

看一下foo.py:

import sysdef bar(i):    if i == 1:        raise KeyError(1)    if i == 2:        raise ValueError(2)def bad():    e = None    try:        bar(int(sys.argv[1]))    except KeyError as e:        print('key error')    except ValueError as e:        print('value error')    print(e)bad()
在Python 2里面可以很好地运行:

$ python foo.py 1key error1$ python foo.py 2value error2
但是在Python 3里:

$ python3 foo.py 1key errorTraceback (most recent call last):  File "foo.py", line 19, in <module>    bad()  File "foo.py", line 17, in bad    print(e)UnboundLocalError: local variable 'e' referenced before assignment
解决方案:

import sysdef bar(i):    if i == 1:        raise KeyError(1)    if i == 2:        raise ValueError(2)def good():    exception = None    try:        bar(int(sys.argv[1]))    except KeyError as e:        exception = e        print('key error')    except ValueError as e:        exception = e        print('value error')    print(exception)good()
在Py3k中运行结果:

<code>$ python3 foo.py 1key error1$ python3 foo.py 2value error2</code>
在 Python招聘指南里有许多关于Python 2与Python 3在移植代码时需要关注的注意事项与讨论,大家可以前往看看。

10.滥用__del__方法

比如这里有一个叫mod.py的文件:

import fooclass Bar(object):   	    ...    def __del__(self):        foo.cleanup(self.myhandle)
下面,你在another_mod.py文件里执行如下操作:

import modmybar = mod.Bar()
你会获得一个AttributeError异常。

至于为什么会出现该异常,点击这里查看详情。当解释器关闭时,该模块的全局变量全部设置为None。因此,在上面这个例子里,当__del__被调用时,foo已经全部被设置为None。

一个很好的解决办法是使用atexit.register()代替。顺便说一句,当程序执行完成后,您注册的处理程序会在解释器关闭之前停止 工作。

修复上面问题的代码:

import fooimport atexitdef cleanup(handle):    foo.cleanup(handle)class Bar(object):    def __init__(self):        ...        atexit.register(cleanup, self.myhandle)
在程序的正常终止的前提下,这个实现提供了一个整洁可靠的方式调用任何需要清理的功能。

总结

Jolla下月展示首款Sailfish手机 将重点发展中国区 海外1GB大容量游戏,国内渠道如何分发? 真正的能源大户是WiFi网络 数据中心只是“伪军” CloudFlare创始人传奇人生:7岁编程,法学博士,获哈佛商学院最高荣誉 2013云计算深入实践 jQuery 2.0发布 不再支持IE 6/7/8 Google再发力,更新Dart M4! 【多图】鼠标、光驱等13个即将消失的PC技术 直击OpenStack美国峰会:分享五大经验收获 Project Savanna:让Hadoop运行在OpenStack之上 看Go桌面技术副总,如何解读Facebook Home 增长最快的游戏公司Supercell 你学得会? 移动周报:为什么我们出不了IT神童? AWS、VMware和OpenStack谁是赢家? 消息称苹果正在寻找新任CEO取代库克 请别人云亦云 PC仍然重要且活得很好 比预想晚几年!IBM x86服务器或终将卖给联想 App推广的节操呢? iMessage垃圾短信产业链暗访 Apkudo CEO访谈:免费为Android开发者提供测试 Web API核查表:设计、测试、发布API时需思考的43件事 开源Android构建工具Buck 速度超Ant两倍 从史上八大MySQL事故中学到的经验 OpenStack Heat向应用市场更近一步 初创公司Ionic Security:云安全必须与时俱进 谷歌董事长:一年后消费者才能用上Goolge Glass Windows 8.1重新推出的“开始按钮”毫无意义 手眼并用 代码泄露三种Google Glass手势操作 Google新论文 CPI&#178;:基于Linux的世界级跨数据中心服务器CPU监控 20款非常实用的Web工具和资源列表 数据库界大事件 随机写性能巨好的TokuDB开源了 CMDN Club 26期:数字渠道营销主题沙龙 系统软件谁居第一 新人“ gxlxwp1982(我爱Delphi,就像老鼠爱大米)”来了,以后大家多帮忙!!!!1 使用Access数据库的SQL语句问题请教!!!! 谁有软件技术测试报告?给我一份参考一下啦~~~ : [求助]请各位帮帮忙呀! weblogic7.0的端口问题 如何在一个form中使用另一个form? win2kp 如何恢复丢失的桌面? 80年出生的都在干什么? SQL Server7.0升级到SQL Server2000 急需winsock2.h文件 delphi开发的程序在WIN2000,WINXP下运行正常,在WIN98却不行,是怎么回事? 如何在TOMCAT下重定向服务器不存在文件的错误页面 关于JFileChooser中的新建文件夹问题? 请问哪里有sun j2ee 服务器参考实现的源程序下载 今年一定考C++吗 考几道C语言的题目啊~~~~~~~~~~~~ VB调用COM接口,出现类型不匹配,如何解决? 关于拷贝构造函数,诡异。。。 如何使窗体永远在所有窗口的最前面! vsftpd 是配好了,但是登陆不上去 请问如何编程以其他用户的身份来运行一个程序? 我在同一ASMX文件中在某个WebMethod中调用其它的WebMethod出错,说不支持关键字“provider” 100分求进、销、存类程序源码 各位,请教一数据访问时间问题 七天七世纪 希望顶级高手能进来-->用streamReader的ReadLine读中文文件时出现乱码! 扩充话题 灌水乐园 与 程序人生 这两个版面在主题上有什么区别? 大家好阿,哪里有 WINDOWS XP操作系統下載,謝謝,最好不要激活, Webserver在引用时候怎样才能引用他的属性如: 来者有分,小问题 如何在自已的DNS服务器上解析两个不同的域名! 替换一个表中的数据的SQL怎么写 请问微星845GLM 如何实现usb启动 请问有人知道用其他程序把NOTES的工作台打开的方法吗??高分求解! 急!!计算机接通电源后什么反映也没有,硬盘不读,显示器不响应,主板不报警,我将显卡和内存反复插n遍以后,亮过一次,再加一根内存又 请问怎样设置文件的大小,才能大于4G. !!!!!!为什么我每次安装office2000到一半的时候,机器就重新启动了啊???????? 急!!计算机接通电源后什么反映也没有,硬盘不读,显示器不响应,主板不报警,我将显卡和内存反复插n遍以后,亮过一次,再加一根内存又 为什么正确的SQL语句运行会死掉??? 求助:求一在线时间统计程序 【投诉扩充话题大版主xmsjms】 使用print#怎样能不产生chr(10)? 如何将一个复选框中的所有选项都存到数据库中? 【公告】看看我的信誉分是怎么减的!特此公告!狂散分 怎么以非模态形式显示窗口? 用jscript的file.Delete()操作时如果不能删除,如何得到返回值,而不是对话框的提示没有权限? 请问:如何获取进程使用的内存使用大小? BCB6中哪儿设置TAB的宽度? 我不知道这是不是一个巨难问题? weblogic服务器里面出现的问题! 八位数一定比七位数大? rate increases是什么意思 五下课文《半截蜡烛》作者 英语翻译2 groups of austrian musicians will arrive in mudanjiang for either one evening of a combined concert on august 14th or august 21st(plan A)or for two separate shows on two different evenings on august 13th,14th ot august 20th,21st(plan B) 父母对孩子要求高,是因为他们很爱自己的孩子.英文 垂直搜索引擎是什么意思? 五下课文1课蒙汉情深何忍别,天涯碧草话斜阳! 1、钟表上分针的走动是( )现象?,人乘电梯是( )现象?船在水面上航行( )现象,推开转动的门是( )现象?2、在一个直径为8厘米的圆中画一个最大的正方形,这个正方形的面积是( )平 三年级数学语文题求解.语文成语填词:善()()()()于()()()()观()()()()察()()()勤()()于()()思()()考()()()数学:将1—12个自然数 利用专家小组法预测某品牌彩电投放市场后头一年销售量,15位专家最后一轮对最高销售量的分析预测值为推断数(台) 1000 900 800 700 600专家人数 2 3 5 3 2要求该市场头年销售量的最高值.可用算术 收款凭证的英语翻译是什么? 女童目睹家人在车祸中被烧死 获赔1.安倍经济学:IMF认为有益经济 日本女子坚持嫁给残障男友 坚贞真爱感动世策划暗杀曼德拉犯罪团伙获重判 主犯拒日媒:安倍将亲自向中国救人留学生颁发萌猫每天造访商店 望着橱窗里老鼠或鱼奥巴马医改网站安全漏洞细节曝光 内测伊拉克向美国请求军事援助 对抗“基地美一客机紧急迫降阿拉斯加偏远小镇 无年轻人使用手机成瘾 或因社交焦虑渴望英媒:美国窃听盟国收益是否大于成本存詹皇:我真的不需要任何额外动力法官被免职 处罚重不重?威少的品味,美国男士的选择!假货帮凶20150608唐师曾:贫血喉舌,仍白色版锤子T1亮相天猫,双12开售再困版权 酷狗难续音乐软件王者梦春节放假纠结在“习惯性多管”赌上惠普未来的忆阻器,是个什么东西?驰援马尔代夫 中国责无旁贷克拉手游获星河互联天使投资 涉金额数墨棱永恒之现代神话魔幻奇异炽炎天下幻想记事本洪荒新传说孤星醉影异风变末世之大剑召唤者最强天才异世之顶峰强者蠡湖大桥旅游金沙岛旅游大行宫旅游石臼湖旅游冷水江波月洞旅游中东铁路博物馆旅游吊桥公园旅游始祖山旅游中国雕塑博物馆旅游月光岛旅游千岛湖中心湖区旅游
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘