看懂报错
对于不少刚学python的小白,遇到python报错后总是一头露水,不知所措。今天这篇文章就带你看懂报错信息。
我们先从一个最简单的一个例子讲起, 除法中分母不能为零
上面的代码1/0会报错,我们来分析一下python所给出的报错信息。
Traceback (most recent call last): File "/home/deng/python/error/test.py", line 1, in <module> a = 1 / 0 ZeroDivisionError: division by zero
可以发现,第2行中告诉了我们出错的文件,出错的行数,分别是test.py文件和第1行,紧接着第3行给出了导致报错的代码内容,第4行给出了报错的原因(报错类型)即除数为0。以上就是python中一个最简单的报错信息,基于这些信息,我们可以快速定位错误位置,并进行修改。下面来看一个稍微复杂的例子。下面的例子里面引入了几个函数,同时函数和函数之间还进行了互相调用,这样是为了模拟一个相对复杂的情况。
同样的,我们也在a函数内部设置了一个1/0的错误。
在分析上面的错误信息之前,首先这里需要了解一个概念,叫做调用顺序(调用栈),比如在b函数中调用了a函数,那么当运行b函数的时候,应该是b函数先运行,然后a函数再运行,这里的先后顺序就是调用栈。你可以将这种先后关系理解为洋葱,最外层的总是比最内层的先被剥掉。在python中,错误信息是按照由外而内的顺序进行输出,即先输出最先报错的地方,然后一层层定位到真正报错的地方。
明白了上面的知识,我们再来看代码和对应的报错信息。代码中c函数调用了b函数,而b函数调用了a函数,所以函数运行的顺序应该是 c > b > a,而错误位于a中,所以报错信息应该是先从c开始,到a结束。左边的报错信息中先是输出了c的报错信息,然后输出了b的报错信息,然后输出了a的报错信息,发现a是真正报错的位置,然后给出了a中报错的行数和对应报错代码。这样就定位了python中真正的错误位置,从而进行相应的修复。
在使用某些第三方的包时,代码报错可能会输出很长很长的错误,这一点是很正常的,对于一个大型的python项目,内部存在十分复杂的调用关系,所以当出现错误时,python会按照这个复杂的调用关系依次输出,其实我们可以直接来看最下面的一个报错信息,就可以定位真正的报错位置了。
学会提问
当你遇到了错误以后,实在是自己解决不了,需要向其他人请求帮助时,一套老练的提问方式十分必要。遇到了报错后,不要慌张,把你的代码和你的报错信息一并发给你请求的人,同时报错信息一定要发全(有些同学可能觉得这个报错信息太长了,只选择了报错信息的前几行,反而把最后的报错信息给遗漏了)。你会发现向别人寻求代码帮助的时候,像极了发生火灾时拨打119报警,你不能一直跟接线员嚷嚷着着火了,着火了,而是要冷静的,将火灾的位置,可能引起火灾的原因告诉对方,这样才能在最短的时间到达火场,处理险情。
常见错误
对于大多数错误,其实你的编辑器(pycharm或者vscode)都可以给出相应的提示,这里列出一些不太能给出提示的错误。
数组越界
a只有3个元素,a[4]则需要保证a中至少含有5个元素
脚本编码错误
有时候,由于代码中存在中文字符,通过windows记事本打开后再保存,可能文件的编码就被换成了中文编码(gb2312),而python默认是使用ASCII码来处理python文件的,这时再运行这个python文件就会报错。你可以在python文件头部加一行# -*- coding: gb2312 -*-
,来指定python以gb2312的方式处理python文件,当然,我还是推荐你使用utf-8的编码来写python文件。
递归爆栈
python中递归有递归深度的限制,在平时的代码编写中应该避免递归的出现,或者修改python默认的递归深度
修改递归深度
使用循环改写递归
一种更常见的递归错误,两个函数之间相互调用,从而导致了爆栈
在定义之前引用
在一个函数内部修改一个外部的全局变量时,应该声明这是一个全局变量
解决方法