python如何Debug?

很高兴见到你!
咱们这一课的标题是“如何Debug?” ,在此之前,我必须先跟你说一个故事。
这个故事和哈佛的一位女数学家格蕾丝·赫伯(Grace Hopper)有关,当时是1955年,那一年,她正在为下面这玩意儿编制程序。
fb 1
这是世界上第一台万用计算机——马克1号(mark1)。你看看这庞大的机器,可想而知,格蕾丝不止要做脑力活儿,还要做体力活儿。
一天,她正在调试程序(就跟我们在电脑上运行代码,看终端有没有报错一样),结果老是出现故障。
层层排查后,她拆开了继电器(体力活儿),结果发现有只飞蛾被夹扁在触点中间,从而“卡”住了机器的运行。
于是,格蕾丝幽默地把程序故障统称为“臭虫(Bug)”,把排除程序故障叫Debug,而这奇怪的“称呼”,后来成为计算机领域的专业行话。因此,Debug就是为程序排除错误的意思。
fb 2
另外,告诉大家一个事实:Debug听上去很专业,但其实你已经学过一些基础debug的方法了。没想到吧?惊不惊喜?意不意外?
当然,Python中还有其他更专业和深入的debug方法,但在这里我们暂时用不到,所以就只讲基础的3种,请看下图:
fb 3 copy
乍一看,可以说这个图的每个字你都认识,我们每个知识点也都学过。但是,现在我们需要从debug的角度来看它们。
先来看print() 函数。这是大家在第0关就接触到的函数,大家已经非常熟悉它的功能了——就是打印内容在屏幕上。
但其实它也能帮我们确认每一步是不是走对了,以排除错误的那一步。
井号注释我们也学过,知道电脑是不会执行代码中的井号和其之后的内容的。
【代码:python3】
print(‘远离颠倒梦想’)
#print(‘究竟涅槃’)
比如这个就只会执行第一行代码,而第二行代码是被计算机忽略的。
因此,当你写的代码总是不对,又弄不明白哪里不对的时候,使用井号把后面的代码注释掉,一步一步运行,可以帮助排除错误。
而print()函数常和井号注释结合在一起用来debug。下面来讲一个例子:
这是一个我们在第8关的选做题。题目是这样的:
fb 4 copy1
然后有同学是这样写的,这是一段错误的代码,大家可以运行看看(记得这里有input() 函数,要在终端输入,然后点击enter):
【代码题:python3】

v = {
'妖猫传':['黄轩','染谷将太'],
'无问西东':['章子怡','王力宏','祖峰'],
'超时空同居':['雷佳音','佟丽娅'],
}

t=input('你查询的演员是?')
for i in v:
    actors=[i]
    if t in actors:
        print=(t+'出演了'+i)

你可以体验到,这个程序是达不到题目要求的效果,可是又没有报错,这时就需要我们debug了。
1-7行感觉不出问题,因为字典的写法挺规范的,都用了英文的符号。
继续看第8行:这位同学想要用for循环遍历这个字典。第9行:这位同学试图取出字典中的值。如果熟悉的人了解,这不符合语法规范。
但是如果他自己不知道的话,这时,就可以用注释和print() 函数来帮助他看看到底是怎么回事,请看下面的第10-12行代码:
【代码:python3】

v = {
'妖猫传':['黄轩','染谷将太'],
'无问西东':['章子怡','王力宏','祖峰'],
'超时空同居':['雷佳音','佟丽娅'],
}

t=input('你查询的演员是?')
for i in v:
    actors=[i]
    print(actors) #使用print() 函数查看操作是否正确。
    #if t in actors:
        #print=(t+'出演了'+i)

我们把后面的代码先注释掉,先不管,先执行前面的代码,并且用print()函数帮我们确定这个这里的操作有没有问题。
运行这段代码,假如用户输入的是’黄轩’,终端会这样显示:
}
fb 5
打印出来了,可见这位同学取到的全部都是键,而非值。这时,就能意识到是这一步出了问题了,他可以回看知识点,发现字典的值的取法,然后修改代码:
【代码:python3】

v = {
'妖猫传':['黄轩','染谷将太'],
'无问西东':['章子怡','王力宏','祖峰'],
'超时空同居':['雷佳音','佟丽娅'],
}

t = input('你想查询哪个演员?')
for i in v:
    actors = v[i]
    if t in actors:
        print(t+'出演了电影'+i)

其实说白了,就是一个语法规范的问题,但新手不就容易被卡在这种地方吗?所以一方面问自己有没有犯一些很基础性的错误,一方面使用print() 函数和人注释也能帮你找到问题,排除错误。
包括在爬虫项目中,你不确定自己取的东西是否正确,都可以打印出来看看。
比如第14关的《重新定义上网冲浪》中,我们用requests模块下载三国演义的小说时也用了print()函数,请看下面代码的第5行:
【代码:python3】

import requests
#引用requests模块
sanguo = requests.get('https://static.pandateacher.com/sanguo.md')
#下载《三国演义》第一回,我们得到一个对象,它被命名为sanguo
print(sanguo.text[:800])
#sanguo.text是对象sanguo的一个用法,代表的是文本内容。我们把它打印出来,只不过整章太长,只输出800字看看就好。在关于list的知识那里,你学过[:800]的用法。

通过打印,我们确认,自己拿到了正确的数据片】
python pc day7 21
确认之后,我们开始用for循环来把《三国演义》写入本地文件, 就可以往下走了。
至于井号注释,可以一行一行帮我们看程序的正确性,这就是print() 和井号注释的妙用啦~.}fb 3 copy 2
如何查看终端的报错信息,我们在第4关布尔值那里专门讲过,我们再次回顾一下:
【代码:python3】

a = input('请输入密码')
if a == 'sweetie'
    print('通过')

如果运行这段代码,终端是会报错的。~}fb 6
你还记得我们要看哪几个地方吗?
首先图里写了,Line2就是第二行代码有问题;然后再看尖尖的三角符号,指向了第二行的最后;再看最后一行:SyntaxError: invalid syntax。
如果搜索百度,最后一行的意思是 语法错误:不正确的语法,然后我们还看到这样的话:
}
fb 7
这一切的证据都指向,条件判断的语法可能写错了,然后你去查看知识图鉴,发现if 的条件后面,一定要加冒号。就这样,问题完美解决。
好,报错你已经非常熟悉了。.}fb 3 copy 3
这个比较适用于控制你已经相对明确的错误类型。
比如在14关《重新定义上网冲浪》里面,我们通过requests模块去下载电子书《三国演义》。
可是编码问题,网上的电子书常有乱码。所以在使用for循环写入本地文件的时候,就容易报错,这时,就可以使用try…except…来debug。请看下面代码的第9-16行:
【代码:python3】

import requests
#引用requests模块
sanguo = requests.get('https://static.pandateacher.com/sanguo.md')
#下载《三国演义》第一回,我们得到一个对象,它被命名为sanguo
k = open('《三国演义》.txt','a+')
#创建一个名为《三国演义》的txt文档,指针放在文件末尾,追加内容
for words in sanguo.text:
#回想一下,循环那里的知识。sanguo.text是字符串,是可遍历的
    try:
    #尝试执行下面的内容。在学习处理异常时,我们了解过try……except……的用法
        k.write(words)
    except:
    #出现报错,则执行:
        pass
        #跳过。pass的意思,就是什么也不执行,通常起占位作用,保证程序格式完整
        #网络上的电子书常有乱码,会导致不能写入报错。所以我们加一个跳过异常防止意外
    continue
    #继续循环
k.close()
#关闭文档

想象一下:如果没有第9-16行代码,直接写入,一遇到乱码,就会写入不了,闹心啊。
在已经知道是编码的问题下,如果你使用了try…except…来为程序排除了错误,就可以继续往下走了,(#^.^#)。
好了,到此,我们就以debug的眼光重新认识了学过的知识。.}fb 3 copy 4
现在,我们不需要再像格蕾丝一样去抓臭虫(bug),但是要靠我们的聪明才智去为代码排除错误。
为程序排除错误,本质上是想办法解决一个问题的过程。这里面有思维的训练,也有心灵的砥砺,这也是乔布斯为什么建议每个人都学编程的理由。
所以,已经解决了很多问题的你,真的真的很了不起!继续加油噢,我的同学!

发表评论