python小白学习笔记《9.编程思维:如何debug》
Bug的故事:
时光回到1947年,当时被誉为计算机程序之母的格蕾丝·赫伯(Grace Hopper)正在为下图这个庞然大物编制程序。
这是世界上第一部万用计算机的进化版——马克2号(Mark II)。瞧瞧这庞大的机器,可想而知,格蕾丝不止要做脑力活儿,还得做体力活儿。
有一天,她正在调试程序(就跟我们在电脑上运行代码,看终端有没有报错一样),结果老是出现故障。
层层排查后,她拆开了继电器,结果发现有只飞蛾被夹扁在触点中间,从而“卡”住了机器的运行。揪出来之后,格蕾丝幽默地把这只幺蛾子的尸体贴在了她的工作日志上,并喊它叫bug(臭虫)。
从此,bug就化身计算机领域里程序故障的代名词,成为程序员一生如影随形的“亲密敌人”。而我们也自然把排除程序故障叫做debug。
Debug听上去很专业,意思其实就是“捉臭虫”,也就是自查和解决代码中的问题。
这一节笔记就来学学怎样debug
0.bug 1:粗心
我们来看第一种类型:由粗心导致的错误代码:
a = input('请输入密码:')
if a == '123456'
print('通过')
这段代码的意思是:如果用户输入123456,屏幕上会打印出“通过”。但运行这段代码,终端会报错:
仔细看可以发现,这段代码的问题是少了一个【英文冒号】
仔细看报错,其中有3个关键信息:
(1)line 2代表这个bug出现在第2行,所以,我们在Debug的时候,可以优先从第2行开始检查。
(2)^代表bug发生的位置,这里指出的位置是第二行末尾。(3)这一行写的是错误类型,SyntaxError指的是语法错误。
一开始可能对错误类型的英文不太熟悉,可以直接复制到百度搜索:
像这样,通过理解报错信息,我们可以快速定位错误的根源。这种阅读、搜索报错信息的能力,在我们以后独立编写愈来愈复杂的程序时显得尤为重要。
开始学编程的时候,因为粗心导致的bug可能所占的比重最大,在这里列出一些新手最容易犯的粗心错误,多有意识地注意以后就能少犯了。
自检清单:
1.漏了末尾的冒号,如if语句、循环语句、函数等;
2.缩进错误,该缩进的时候没缩进,不该缩进的时候缩进了;
3.把英文符号错写成中文符号;
4.字符串拼接的时候,把字符串和数字拼接在一起;
5.没有定义变量;
6.‘==’和‘=’混用
1.bug 2:知识不熟练
第二种bug:由于知识不够熟练而引起的错误
某学员建了一个空列表a,希望往里面增加3个值,让最后的列表变成 [‘A’,‘B’,‘C’],但写出的代码有误:
a = []
b = a.append['A','B','C']
print(b)
这里的问题出在append()函数,append()函数的相关知识,或者搜索“python append”,可以知道,并没有a=append(‘A’,‘B’,‘C’) 这种用法。
append()函数是列表的一个方法,要用句点.调用,且append()每次只能接受一个参数,所以正确的写法是这样:
a = []
a.append('A')
a.append('B')
a.append('C')
print(a)
这种bug给我们的启示是:当你发现知识点记不清或者不能确定的时候,就要及时复习或者上网搜索。不要强行写出自己不敢确定的代码,这种情况往往容易出错。
如果对某个基础知识点没有熟练的掌握,随着往后知识广度、深度以及项目难度的增加,很可能会增加大量的理解成本,所以多复习、多练习总是没有错滴。
2.bug 3:思路不清
思路不清指的是当我们解决比较复杂的问题时,由于我们对细节和实现手段思考得不够清楚,要么导致一步错,步步错;要么虽然没有报错,但是程序没有达到我们想要的效果。
解决思路不清的两个工具:
1.print()函数;
2.用#注释掉部分代码
print()函数能成为我们检验对错的里程碑:遇到关键步骤时print出来,看是否达到我们所期望的结果,以此来揪出错误的那一步。
计算机不会执行代码中的#号和其之后的内容。
因此,当写的代码总是不对,又弄不明白哪里不对的时候,使用#号把后面的代码注释掉,一步一步运行,可以帮助排除错误。
print()函数常和#号注释结合在一起用来debug。
来找茬:
以下代码是一位同学写的一个猜硬币游戏,一共有两次猜的机会:
import random
guess = ''
while guess not in ['正面','反面']:
print('------猜硬币游戏------')
print('猜一猜硬币是正面还是反面?')
guess = input('请输入“正面”或“反面”:')
# 随机抛硬币,0代表正面,1代表反面
toss = random.randint(0,1)
if toss == guess:
print('猜对了!你真棒')
else:
print('没猜对,你还有一次机会。')
guess = input('请再输一次“正面”或“反面”:')
if toss == guess:
print('你终于猜对了!')
else:
print('你猜错啦,没有机会咯!')
但是,这位同学可能没有想清楚代码的逻辑,导致这个程序有个致命问题:用户永远都不可能猜得对。
那要如何把这段代码修改正确呢?
这里的主要问题是:
toss会随机生成0或1,而guess会是“正面”或“反面”,导致toss不可能等于guess,条件判断永远为假。
针对这个问题,第一种方法是先创建一个列表:
import random
all = ['正面','反面']
guess = ''
while guess not in all:
print('------猜硬币游戏------')
print('猜一猜硬币是正面还是反面?')
guess = input('请输入“正面”或“反面”:')
# 随机抛硬币,0代表反面,1代表正面
toss = all[random.randint(0,1)]
if toss == guess:
print('猜对了!你真棒')
else:
print('没猜对,再给你一次机会。')
guess = input('请再输一次(“正面”或“反面”):')
if toss == guess:
print('你终于猜对了!')
else:
print('你猜错啦,没有机会咯!')
第二种更为取巧,直接把输入的信息限定为’0’或’1’:
import random
guess = ''
while guess not in [0,1]:
print('------猜硬币游戏------')
print('猜一猜硬币是正面还是反面?')
guess = int(input('“正面”请输入0,“反面”请输入1:'))
#注意要用int()将字符串类型转换为数字类型
toss = random.randint(0,1)
if toss == guess:
print('猜对了!你真棒')
else:
print('没猜对,再给你一次机会。')
guess = int(input('请再输一次(“正面”请输入0,“反面”请输入1):'))
if toss == guess:
print('你终于猜对了!')
else:
print('你猜错啦,没有机会咯!')
3.bug 4:被动掉坑
被动掉坑,是指有时候你的代码逻辑上并没有错,但可能因为用户的错误操作或者是一些“例外情况”而导致程序崩溃。
举个例子,当运行以下代码的时候,如果输入的东西不是数字,则程序一定会报错:
age = int(input('你今年几岁了?'))
if age < 18:
print('不可以喝酒噢')
当我们输入的不是数字,程序会这样报错:
这里的“ValueError”的意思是“传入无效的参数”。因为,int()函数不能接受非数字的字符串。
为了不让一些小错影响程序的后续执行,Python给我们提供了一种异常处理的机制,可以在异常出现时即时捕获,然后内部消化掉,让程序继续运行。
这就是try…except…语句,具体用法如下:
try:
#尝试执行以下代码
.....
.....
#代码要缩进
except ***:
#除非发生***形式报错,就执行以下代码:
.....
.....
#代码要缩进
举个例子
刚才的报错,可以查到报错类型是“ValueError”:
try:
age = int(input('请输入一个整数:'))
except ValueError:
print('要输入整数噢')
终端:
这样就不会报错了
修改上一个例子:
while True:
try:
age = int(input('你今年几岁了?'))
break
except ValueError:
print('你输入的不是数字!')
if age < 18:
print('不可以喝酒噢')
代码要点有两个:
(1)因为不知道用户什么时候才会输入正确,所以设置while循环来接受输入,只要用户输入不是数字就会一直循环,输入了数字就break跳出循环。
(2)使用try……except……语句,当用户输错的时候会给予提示。
关于Python的所有报错类型,有需要的话可以在这里查阅:
Python 异常处理