400-616-5551

您所在位置: 首页> 学习课程> python培训 | Python程序调试常见错误排查,学会它效率翻倍

python培训 | Python程序调试常见错误排查,学会它效率翻倍

发布百知教育 来源:学习课程 2019-11-08

在编写并调试Python程序的过程中,总会遇到这样或那样的错误,其中绝大多数错误都是由于用户粗心或语法错误引起的。本文将详细讲解排查Python程序错误的知识。


Python 2升级Python 3发生的错误

在当今市面中,Python有2.7和Python 3.x两个大的版本分支。在网络教程、教学文档和出版图书中有很多是用Python 2.7实现的,而我们本书是用Python 3.6实现的。当我们直接将Python 2.7代码运行在Python 3.6环境中时,可能会发生一些语法错误。

1 print变成了print()

在Python 2版本中,print是作为一个语句使用的,在Python 3版本中print()作为一个函数出现。下面通过两段代码来展示两个版本的区别。
Python 2.x版本代码如下:

1>>> i = 1
2>>> print 'Python' 'is''number', i
3Pythonis number 1

Python 3.x版本代码如下:

1>>> i = 1
2>>> print('Python' 'is''number', i)
3Pythonis number 1

也就是说,在Python 3版本中,所有的print内容必须用小括号括起来。

2 raw_input变成了input

在Python 2版本中,输入功能是通过raw_input实现的。而在Python 3版本中,是通过input实现的。下面来看两行代码的区别:

1name = input('What is your name?\n') #python3版本的代码
2name = raw_input('What is your name?\n') # python2版本的代码

3 整数及除法的问题

初学者在编写Python程序时,特别是将Python 2程序在Python 3环境下运行时,很可能会遇到“TypeError: 'float' object cannot be interpreted as an integer”错误。例如下面的代码是在Python 2运行成功的:

1batch = 200
2for x in range(len(order_nos) / batch + 1):
3      # do something

其中,order_nos是订单列表,而在Python 3环境下运行时会提示“TypeError: 'float' object cannot be interpreted as an integer”错误,意思是float类型不能解释为int类型。这是因为在Python 3中,int和long统一为int类型,int表示任何精度的整数。在以前的Python 2版本中,如果参数是int或者是long的话,就会返回相除后结果的向下取整(floor),而如果参数是float或者是complex的话,那么就会返回相除后结果的一个恰当的近似。当使用int超过本地整数大小时,不会再导致OverflowError异常。long类型在Python 3中已经消失,并且后缀L也已经弃用。


下面是两个版本的除法对比:
1>>>1/2   #Python 2版本中的结果是0
2>>>1/2   #Python 3版本中结果是0.5,这样比较合理

与之相对应的是,除法也发生了变化,Python 3中的“/”总是返回一个浮点数,“//”永远表示向下除法。所以当涉及除法“/”操作遇到“TypeError: 'float' object cannot be interpreted as an integer”错误时,只需将“/”修改为“//”即可。

4 异常处理大升级

在Python 2程序中,捕获异常的格式如下:

1except Exception, identifier

在Python 3程序中,捕获异常的格式如下:

1except Exception as identifier

例如,下面是Python 2捕获异常的演示代码:

1except ValueError, e: # Python 2处理单个异常
2except (ValueError, TypeError), e:  # Python 2处理多个异常

而下面是Python 3捕获异常的演示代码:

1except ValueError as e:       # Python3处理单个异常  
2except (ValueError, TypeError) as e: # Python3处理多个异常

在Python 2程序中,抛出异常的格式如下:

1raise Exception, args

在Python 3程序中,抛出异常的格式如下:

1raise Exception(args)

例如,下面两行代码演示了两种版本抛出异常的方法:

1raise ValueError, e      # Python 2.x 的方法 
2raise ValueError(e)      # Python 3.x 的方法

5  解决“NameError: name ‘xrange’ is not defined”错误提示

这个错误也是版本问题,Python2使用的是xrange()函数,在Python3版本被range()函数代替。所以在Python 3程序中,只需将xrange修改为range即可解决这个问题。

6  解决“name 'reload' is not defined和AttributeError: module 'sys' has no att”错误提示

在Python 3.6程序中不能直接使用reload,要想兼容Python 2中的reload功能,需要加入如下所示的代码:

1import importlib
2importlib.reload(sys)

7 解决“python unicode is not defined”错误提示

在Python 3程序中经常会遇到“python unicode is not defined”错误提示,这是因为在Python 3中已经没有了unicode类型,被全新的str类型所代替。而Python 2中原有的str类型,在Python 3中被bytes所代替。

8 解决“AttributeError: 'dict' object has no attribute 'has_key'”错误提示

例如,下面的报错过程:

1>>> d={}
2>>> d.has_key('name')
3Traceback (most recent call last):
4  File "<pyshell#1>", line 1in <module>
5     d.has_key('name')
6AttributeError: 'dict' object has no attribute 'has_key'

这是因为在Python 3中已经舍弃了has_key,修改方法是用in来代替has_key,修改为:

1>>> d={}
2>>'name' in d
3True

9 解决“ImportError: No module named urllib2”错误提示

在Python 3中urllib2已经被urllib.request替代,所以解决方法是将urllib2修改为urllib.request。

常 见 错 误

1 解决“IndentationError:excepted an indented bloc”错误提示

这是一个初学者经常犯的错误,这个错误会让人欲哭无泪!这个错误并不是语法错误的问题,而是用户代码书写规范的问题。因为Python是一个对代码缩进非常敏感的语言,整个循环结构可能是依靠缩进的形式来表示的。
初学者最常见的错误就是混用Tab和Space键实现代码缩进,这是很容易报错的,而且肉眼很难分辨出来。虽然很多IDE编辑器可以选择显示空格,但是即便是这样,也很难找到到底哪里有问题。所以建议读者在程序中只使用Tab键实现代码缩进,或者只使用Space键实现代码缩进。
另外,上面的报错还有一个原因经常遇到,就是无首行缩进,例如在编写if语句时在后面加冒号,如果直接换行,好的代码编辑器会自动首行缩进。但是有些代码编辑器可能没有这个功能,这时需要开发者手动缩进,这最好养成习惯。请大家不要连续敲几次空格键,建议直接按一下Tab键即可。

2 解决“no module named XX”错误提示

毫无疑问,这个错误将是读者在学习和开发过程中遇到的最多的错误,没有之一。随着读者开发水平的提高和程序复杂性的提升,将会在程序中用到越来越多的模块和第三方库。那时候将会经常遇到“no module named XX”错误,这个错误的原因是没有安装库“XX”。当遇到这个错误的时候,需要使用如下命令安装库XX:

1pip install ww

3 解决“TypeError: 'tuple' object cannot be interpreted as an integer”错误提示

请看下面的代码:

1t=('a','b','c')
2 for i in range(t):
3 print(t[i])

上述代码会报错:TypeError: 'tuple' object cannot be interpreted as an integer
这是一个典型的类型错误问题,在上述代码中,range()函数期望的传入参数是整型(integer),其但是却传入的入参为元组(tuple)。解决方法是将入参元组t改为元组个数整型len(t)类型即可,例如将上述代码中的range(t)改为range(len(t))。

4 解决“IOError: File not open for writing”错误提示

这是一个典型的文件操作权限问题,例如下面的演示代码会爆出这个错误:

1>>> f=open("hello.py")
2>>> f.write("test")
3Traceback (most recent call last):
4File "<stdin>", line 1in <module>
5IOError: File not open for writing

出错原因是在没有在open("hello.py")的传入参数中添加读写模式参数mode,这说明默认打开文件的方式为只读方式,而在上述代码中需要写入字符操作功能,所以出现权限受限问题,才会报错。解决方法是更改模式mode,修改为写入模式权限w+:

1>>> f=open("hello.py",'w+')
2>>> f.write("test")

5 解决“SyntaxError:invalid syntax”错误提示

这个错误通常是由于忘记在if、elif、else、for、while、class和def等语句末尾添加冒号“:”引起的,例如:

1if spam == 42 print('Hello!')

解决方法是在最后添加冒号“:”。
还有一种情况也会引发上述错误,错误的使用了=,而不是==。在Python程序中,=是赋值操作符,而==是等于比较操作。

6 解决“TypeError: 'str' object does not support item assignment”错误提示

这个错误通常是由于尝试修改string的值引起的,string是一种不可变的数据类型。例如在如下代码中会发生该错误:

1spam = 'I have a pet cat.' 
2spam[13] = 'r' print(spam)

修改方法是:

1spam = 'I have a pet cat.' 
2spam = spam[:13] + 'r' + spam[14:] print(spam)

7 解决“TypeError: Can't convert 'int' object to str implicitly”错误提示

这个错误通常是由于尝试连接非字符串值与字符串引起的,例如在如下代码中会发生该错误:

1numEggs = 12 
2print('I have ' + numEggs + ' eggs.')

解决方法是修改为:

1numEggs = 12 
2print('I have ' + str(numEggs) + ' eggs.')

也可以修改为:

1numEggs = 12 
2print('I have %s eggs.' % (numEggs))

8 错误的使用类变量

考虑下面的演示过程:

1>>class A(object):
2         x = 1 
3>>class B(A):
4         pass
5>>class C(A):
6         pass
7>>> print(A.x, B.x, C.x)
81 1 1
9>>> B.x = 2
10>>> print(A.x, B.x, C.x)
111 2 1
12>>> A.x = 3
13>>> print(A.x, B.x, C.x)
143 2 3

我们只修改了A.x,为什么C.x也被改了?在Python程序中,类变量在内部当做字典来处理,其遵循常被引用的方法解析顺序(MRO)。所以在上面的代码中,由于class C中的x属性没有找到,它会向上找它的基类(尽管Python支持多重继承,但上面的例子中只有A)。换句话说,class C中没有它自己的x属性,其独立于A。因此,C.x事实上是A.x的引用。

9 错误地理解Python的作用域

Python是基于LEGB来进行作用于解析的,LEGB是Local, Enclosing, Global, Built-in的缩写。看起来“见文知意”,对吗?实际上,在Python中还有一些需要注意的地方,先看下面一段代码:

1x = 10
2def foo():
3     x += 1
4     print(x)
5foo()
6
7Traceback (most recent call last):
8  File "<pyshell#62>", line 1in <module>
9     foo()
10  File "<pyshell#61>", line 2in foo
11     x += 1
12UnboundLocalError: local variable 'x' referenced before assignment

上述代码出错的原因是:局部变量x没有初始值,外部变量x不能引入到内部。
再看下面列表操作的情况:

1>>> lst = [1,2,3]  # 给列表lst赋值
2>>> lst.append(4)  # lst后边append一个元素4
3>>> lst
4[1234]
5>>> lst += [5]     # 两个列表合并
6>>> lst
7[12345]
8>>
9def foo1():
10     lst.append(6# 函数会查找外部的lst列表
11>>> foo1()
12>>> lst
13[123456]
14>>
15def foo2():
16     lst += [6]  # 合并列表时,不会查找外部列表,让人有些不可思议吧
17>>> foo2()
18Traceback (most recent call last):
19  File "<pyshell#82>", line 1in <module>
20     foo2()
21  File "<pyshell#81>", line 2in foo2
22     lst += [6]
23UnboundLocalError: local variable 'lst' referenced before assignment

上述代码的出错原因和前面的例子相同,不过更加令人难以捉摸。foo1没有对lst进行赋值操作,而foo2做了。要知道,lst += [5]是lst = lst + [5]的缩写,我们试图对lst进行赋值操作(Python把他当成了局部变量)。此外,我们对lst进行的赋值操作是基于lst自身(这再一次被Python当成了局部变量),但此时还未定义,因此出错!


python培训:http://www.baizhiedu.com/python2019


注释:本文内容来自公众号 异步图书

上一篇:python培训 | 用python看双11手机降价情况

下一篇:应届生去公司找个Java程序员的职位需要什么技能?

相关推荐

www.baizhiedu.com

有位老师想和您聊一聊

关闭

立即申请