我们找了一本Python教程,按照书上的例子一行一行敲下来,结果一运行却出错了。报错对于初学编程的人来说是恐惧的。那么如何应对常见的几类错误。
缩进错误
在Python程序中,不需要用“{}”来表示一个语句体,也不需要用“;”来表示一个语句的结束。Python对程序的缩进有着严格的要求,但你有时候却并不容易发现缩进问题。
如图1.16所示,程序看上去没有任何问题,但运行的时候却出现了“IndentationError:unindent does not match any outer indentation level”的错误。其实错误信息描述,已经很清楚了,但新手往往很难发现错误的原因。
图1.16 Python程序报错
如果将程序全选(快捷键Ctrl+a),就会发现错误,如图1.17所示。在add()函数的语句体中,“c=a+b”前面是一个Tab的间距,而“return c”前面是四个空格的间距。所以,虽然看上去缩进是对齐的,但它们却使用了不同的缩进方法,因而会导致Python执行错误。
图1.17 Sublime Test中的全选
引包错误
引包错误也是新手经常遇到的一类问题,但这其中有一个大坑。
import unittest
class test (unittest.TestCase):
pass
运行程序。
Traceback (most recent call last):
File "D:\pydemo\unittest.py",line 1,in <module>
import unittest
File "C:\pydemo\unittest.py",line 3,in <module>
class test(unittest.TestCase):
AttributeError:model 'unittest' has no attribute 'TestCase'
我们要引用的明明是Python自带的unittest模块,然而程序却提示“module ‘unittest’has no attribute TestCase”。这个错误与Python的引包机制有关,当在程序中“import”一个模块或库时,Python首先会查找当前目录下是否存在同目录的Python文件,如果存在则会优先引用当前目录下的同名文件。
显然,我把自己写的程序文件命名为了“unittest.py”,在程序中又引用“unittest”,那么这就相当于自引用了。而我的真实意图是引用Python的unittest模块。当然,有时也不一定是自引用,也可能是程序的所在目录下出现了重名文件或目录。所以,在给编写的程序文件命名时一定要注意。
编码错误
在开发Python程序的过程中,会涉及三个方面的编码,具体如下。
(1)Python程序文件编码
编写的程序本身也存在编码,一般可以在程序的开头加上“#coding=utf-8”或“#coding=gbk”,使程序统一为UTF-8或GBK编码。
(2)Python程序运行环境(IDE)编码
不管是Python自带的IDLE或是PyCharm,使用的IDE本身也会有编码。所以要清楚地知道自己的IDE所使用的编码。
(3)Python程序读取外部文件、网页的编码。
最容易出现编码问题的情况应该是Python读取外部文件、网页的时候。首先要确定读取的文件、网页的编码格式,然后通过decode()和encode()方法来进行编码转换。
decode的作用是将其他编码的字符串转换成Unicode编码。
encode的作用是将Unicode编码转换成其他编码的字符串。
当我们再遇到Python的编码问题时,从以上三个方面分析就可以很容易地解决了。
学会分析错误
新手往往在看到程序抛出的一大堆报错时会变得手足无措,比起一大堆的报错,最难解决的问题是没有任何报错信息,而程序却无法正确地执行。如果能正确认真阅读报错信息,一般会很容易找到出现错误的原因。
......
Traceback (most recent call last)
File "C:\Python35\lib\site-packages\diango\core\handlers\exception.py",
line 39, in inner
response = get_response(request)
File "C:\Python35\lib\site-packages\django\core\handlers\base.py",line 249,
in _legacy_get_responce
responce = self._get_response(request)
File "C:\Python35\lib\site-packages\django\core\handlers\base.py",line 187,
in _get_responce
responce = self.process_exception_by_middeware(e,request)
File "C:\Python35\lib\site-packages\django\core\handlers\base.py",line 185,
in _get_responce
responce = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Python35\lib\site-packages\django\contrib\auth\decorators.py",
line 23, in _wrapped_view
return view_func(request, *args, **kwargs)
File "D:\git\guest\sign\views.py",line 85,in search_phone
print(phone)
NameError:name 'phone' is not defind
上面是Django的一段报错信息。在分析报错信息时,一般要遵循以下两点。
(1)找到自己写的程序。所以前面的一大段信息就没必要看了;根据倒数第三行的提示:“File ”D:\git\guest\sign\views.py", line 85,in search_phone"(views.py 文件的倒数第85行,在search_phone函数中,找到自己写的代码“print(phone)”)。
(2)看最终的错误提示。最终的提示为“NameError: name 'phone' is not defind”。"NameError"为错误类型,根据错误类型可以锁定错误范围。“name ‘phone’is not defined”为错误提示(名字‘phone’没有定义)。结合第一点找到自己写的程序,显然,print()打印的‘phone’变量没有定义。
搜索微信公众号:TestingStudio霍格沃兹的干货都很硬核