整理一套错误检查清单将在你未来编程时提供很大的助力。
语法错误由python在将源代码翻译为字节的过程中产生。例如在def语句的末尾漏电冒号会产生一个冗余的错误信息:
def repeat_lyrics():
print_lyrics()
print_lyrics()
repeat_lyrics()
def print_lyrics() #漏掉了冒号
print('hello world')
报如下错误,SyntaxError语法错误的提示
File "", line 6
def print_lyrics()
^
SyntaxError: invalid syntax
语法错误在知道怎么修改后往往都比较容易修正,但是,错误信息往往没有什么帮助,最常见的错误信息就是SyntaxError: invalid syntax(无效数据)和SyntaxError: invalid token(无效记号),都没什么信息量,只能自己找到相应的行检查。
需注意的是,语法错误虽然指出了出错的位置,但指出的位置并不一定就是发成错误的位置,有时候错误发生的位置是错误信息指明的位置之前,往往是前一行。
下面是一些可以避免最常见的语法错误的方法:
michael='Eric,the half a bee #少于个引号
print_twice(michael)
File "", line 1
michael='Eric,the half a bee
^
SyntaxError: EOL while scanning string literal
#在增加边长平方变量后依然返回成功,下面计算斜边长的平方
def hypotenuse(a,b):
square_a=a**2
square_b=b**2
square_c=square_a+square_b
print('斜边长的平方为:'+str(square_c)) #忽略了字符串必须和字符串之间用加号,直接用square_c,两个类型不一样不可用加号
return 0
这种情况本来没有加str,后面需要转换为字符串时,容易在前面加str然后括号,到右侧添加括号时会出现你以为添加右侧括号了,实际上编辑器只是把光标移出括号的情况,需要再添加一次。
我一直修改,但没有什么区别
这个我经常遇到,如果解释器报错的一个错误而你找不到,有可能是因为解释器和那你用的并不是同一套代码,检查你的编程环境,确保你正在编辑的代码和python运行的是同一个。出现这种问题有可能是以下原因:
如果你遇到困难被卡住,并弄不清楚是怎么回事,一个办法是重新以最简单的类似“hello world!”的程序开始,并确保你能让一个已知的程序运行,然后逐渐添加原先程序的部分到新程序中。
我自己看了下自己以前的语法错误:
#使用for循环遍历字符串
index=0
for index<len(fruit):
print(fruit[index])
index+=1
File "", line 3
for index
这个是因为把for循环和while循环弄混了,for循环不能用条件判断的
def qiuzhi(k):
jieguo=(factorial(4k)*(1103+26390*k))/(factorial(k)**4*396**(4*k))
while jieguo<1e-15:
break
jieguo=jieguo+(factorial(4(k+1))*(1103+26390*(k+1)))/(factorial(k+1)**4*396**(4*(k+1)))
return jieguo
qiuzhi(0)
File "", line 2
jieguo=(factorial(4k)*(1103+26390*k))/(factorial(k)**4*396**(4*k))
^
SyntaxError: invalid syntax
这个就比较典型了,我这不好的习惯想把所有内容写到一行里,导致代入数据结果正常显示,但是公式就是报错,最后也没找出错在哪,把这一整行分割赋值变量变成几行就没报错了,这个还容易忘了括号等问题。
这个问题最常见的原因是你的文件包含了各种函数和类的定义,但没有实际调用任何代码来启动执行。
比如写了一个函数,但是没有调用
#用最简单的函数确定函数式子可行,然后下一步增加边长平方的变量
def hypotenuse(a,b):
square_a=a**2
square_b=b**2
print(square_a)
print(square_b)
return 0
如果是运行上面代码是没有任何反应的,因为没有调用函数
hypotenuse(3,4)
只有通过调用函数,才会有正常的返回值。、
如果你不确认程序中执行流程如何走向,可以在每个函数开头添加一个print语句,打印类似“进入函数foo”之类的输出,foo指得是函数名。
如果一个程序突然停止看起来什么都没做,在jupyter notebook就是左侧一直显示星号,下面没有输出值,它就有可能卡死了。常见的原因是死循环和无限递归。
无限循环问题解决办法:
如果怀疑某个特别的循环,可以在循环开始前添加一个“进入xx循环”的print语句,在循环结尾处添加一个“退出xx循环”的print的语句。在运行程序如果只看到第一个没看到第二个证明进入死循环了。这其实是一个比较好的习惯,可以在每次写循环的时候都添加上。
如果你觉得有个无限循环但并不知道哪个循环导致了问题,可以在循环结尾处添加一个print语句,打印出循环条件中的变量值,以及条件的值。
while x>0 and y<0:
print('x:',x)
print('y:',y)
print('condition:',(x>0 and y<0))
现在当你再次运行程序时,正常情况是每次循环看到三次打印最后打印false,如果一直循环你可以从打印的值里找出问题。
无线递归问题解决办法:
大部分情况下,无限递归都会在程序运行一会儿后产生“Maximum recursion depth exceeded”的错误。可以先检查来保证有一个条件能导致函数或方法直接返回而不再继续递归调用。如果没有,那么你可能需要冲洗思考算法,并设定一个退出条件。
def countdown(n):
if n<=0:
print('Blastoff!')
else:
print(n)
countdown(n-1)
countdown(3)
上面是一个简单的递归情况,直接返回的条件就是n<=0,检查你的递归中是否有这种类似的条件,没有的话就会产生无线递归的情况。
如果有这种条件,但还是报错,有可能是因为系统的默认递归次数太少,默认999次,可以自行修改一下,但是如果修改了还不行,可以在函数或方法的开头加一个print语句来打印参数,会看到每次函数调用都会打印几行输出,并能看到每次调用的参数,如果参数没有向触发直接返回的条件变化,大概也就发现问题所在了。
NameError:
这种是我经常遇到的,打印错误单词,print写成了pirnt,有时候写快了就容易出这种错误,长单词少写个字母等。总之就是试图使用一个当前环境中不存在的变量。还有个要注意的是,函数内部的局部变量不能在定义他们的函数之外使用它们。
TypeError:
有三种可能的原因:
a=[1,2,3,4]
a[1.1]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
1 a=[1,2,3,4]
----> 2 a[1.1]
TypeError: list indices must be integers or slices, not float
'%d %d %d'%(1,2)#两边个数必须相等
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 '%d %d %d'%(1,2)
TypeError: not enough arguments for format string
'%d'%'dollors'#类型也要一致
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 '%d'%'dollors'
TypeError: %d format: a number is required, not str
#内置函数divmod接收两个参数,并返回两个值的元组,商和余数
t=(7,3)
divmod(t)#改成*t就可以了
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
1 t=(7,3)
----> 2 divmod(t)
TypeError: divmod expected 2 arguments, got 1
#练习:编写一个函数sumall,接收任意个数的参数并返回它们的和
def sumall(t):
return sum(*t)
t=(1,2,3,4)
sumall(t)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
3 return sum(*t)
4 t=(1,2,3,4)
----> 5 sumall(t)
in sumall(t)
1 #练习:编写一个函数sumall,接收任意个数的参数并返回它们的和
2 def sumall(t):
----> 3 return sum(*t)
4 t=(1,2,3,4)
5 sumall(t)
TypeError: sum expected at most 2 arguments, got 4
sum只需要两个参数,这边却给了四个。
sum(1,2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 sum(1,2)
TypeError: 'int' object is not iterable
sum需要接收第一个参数是一个列表或元组等。
def is_anagram(word1,word2):
if "".join(list(word1).sort())==word2 or "".join(list(word2).sort())==word1:
return True
return False
is_anagram('hello','ab')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
3 return True
4 return False
----> 5 is_anagram('hello','ab')
in is_anagram(word1, word2)
1 def is_anagram(word1,word2):
----> 2 if "".join(list(word1).sort())==word2 or "".join(list(word2).sort())==word1:
3 return True
4 return False
5 is_anagram('hello','ab')
TypeError: can only join an iterable
这里是因为sort()没返回值,是Nonetype,不符合join参数类型。
KeyError:
用一个字典不包括的键来查找字典的元素。
items={'a':1,'b':2,'c':3}
items['d']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
in
1 items={'a':1,'b':2,'c':3}
----> 2 items['d']
KeyError: 'd'
显然这个报错并没有给出太多的信息,只能按照位置自己看一下了,想要找到问题所在得知道KeyError出现的原因是什么。
AttributeError:
在访问一个并不存在的属性或方法。检查拼写,可以使用dir函数来列出存在的属性。
#练习:编写一个函数is_anagram,接收两个字符串,当它们互为回文时返回True
def is_anagram(word1,word2):
if word1.sorted()==word2:
return True
return False
is_anagram('ab','ba')
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in
4 return True
5 return False
----> 6 is_anagram('ab','ba')
in is_anagram(word1, word2)
1 #练习:编写一个函数is_anagram,接收两个字符串,当它们互为回文时返回True
2 def is_anagram(word1,word2):
----> 3 if word1.sorted()==word2:
4 return True
5 return False
AttributeError: 'str' object has no attribute 'sorted'
看到str没有sorted那改成sort(),结果还是相同错误。当时不知道这个类型错误的处理办法,只能瞎试了。
t=[1,2,3]
t.find(1)
#想直接用用find方法,结果不行
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in
1 t=[1,2,3]
----> 2 t.find(1)
3 #想直接用用find方法,结果不行
AttributeError: 'list' object has no attribute 'find'
#练习:编写一个函数rotate_word,接收一个字符串以及一个整数作为参数,并返回一个新字符串,其中字母按照给定的整数值轮转位置
def rotate_word(word,num):
new_word=''
for letter in word:
new_word.append(chr(ord(letter)+num))
return new_word
rotate_word('a',1)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in
5 new_word.append(chr(ord(letter)+num))
6 return new_word
----> 7 rotate_word('a',1)
in rotate_word(word, num)
3 new_word=''
4 for letter in word:
----> 5 new_word.append(chr(ord(letter)+num))
6 return new_word
7 rotate_word('a',1)
AttributeError: 'str' object has no attribute 'append'
如果AttributeError指明一个对象是Nonetype,则意味着它是None.这种问题的一个常见原因是忘记返回或用print替代了返回。如果函数执行语句到结尾都没有遇到return语句,那么它会返回None。另一个常见的原因是使用了一个返回None的列表方法作为结果,比如sort。所以注意print和return的区别,以及注意一个方法是否有返回值是比较重要的事。
IndexError:
在访问列表、字符串或元组时使用的索引大于它的长度减一。在错误发生前一行,添加一个print语句展示索引的值和数组的长度。数组长度是否正确,索引大小是否正确。
a=[1,2,3,4]
a[4]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
in
1 a=[1,2,3,4]
----> 2 a[4]
IndexError: list index out of range
更容易出错的情况是在for i in range(len(list)):
这种情况时,有时候需要减一,有时候不需要减一,这个需要根据循环里的内容做判断,容易出错。
语义错误是正常返回值但是和预期不一样的错误。从某种角度来说,语义错误更难调试。因为解释器并不提供任何错信息,只有你自己知道程序到底应该怎么做。
解决语义错误的第一步是在程序文本和你看到的程序行为之间建立一个连接。你需要对程序实际在做什么有一个假设。让这件事变得很难的原因是计算机运行得太快。
在合适的位置插入print语句依然是最简单有效的检查问题的方法
你应该问自己如下几个问题:
为了能够编程,你需要对程序如何工作,有一个思维模型。如果编写出一段和你预料不一样的代码,常常问题不是在程序本身,而是在你的思维模型上。
修正你的思维模型的最佳方法是将程序划分成不同部分(通常是函数和方法)并独立测试每一部分。一旦找到你的模型和真实世界的偏差,就能够解决问题了。
当然,在开发程序时,你应当分组件进行构建和测试。如果发现一个问题,应当只需要检查一小部分新的不确认是否正确的代码。
编写复杂表达式也有可能出问题,难读,难调试。另一个问题是求值的顺序可能和你期望的也不一样。将复杂表达式拆分成一系列复制到临时变量的语句,常常是好主意。
def estimate_pi():
def factorial(n):
if n==0:
return 1
else:
recurse=factorial(n-1)
result=n*recurse
return result
a=0
k=0
while (factorial(4k)*(1103+26390*k))/(factorial(k)**4*396**(4*k))>=1e-15:
a+=(factorial(4k)*(1103+26390*k))/factorial(k)**4*396**(4*k)
k=k+1
return a
daoshu=2*math.sqrt(2)/9801*a
pi=1/daoshu
return pi
estimate_pi()
File "", line 11
while (factorial(4k)*(1103+26390*k))/(factorial(k)**4*396**(4*k))>=1e-15:
^
SyntaxError: invalid syntax
拆分了好几次代码,这个复杂公式总是出错,后来把公式拆了就没问题了
import math
def factorial(n):
if n==0:
return 1
else:
recurse=factorial(n-1)
result=n*recurse
return result
def estimate_pi():
total=0
k=0
factor=2*math.sqrt(2)/9801
while True:
num=factorial(4*k)*(1103+26390*k)
den=factorial(k)**4*396**(4*k)
term=factor*num/den
total+=term
if abs(term)<1e-15:
break
k+=1
return 1/total
print(estimate_pi())
有时候自己实在想不出来了,可以暂时离开电脑休息下,也许过段时间就找到问题所在了。
实在找不到错误需要别人帮助的情况也是存在的,这时请确保你已经准备好了。你的程序应当尽量简单,而你应当使用最小的输入来复现错误。你应当在合适的地方放好了print语句(并且他们的输出应当容易理解),你应当足够理解这个问题,因此能够简明扼要的描述它。
当你找人帮忙时,请确保给他们需要的信息:
我们的目标不只是让程序正确运行,目标是学会如何让程序正确运行。