鱼C论坛

 找回密码
 立即注册
查看: 1858|回复: 1

[萌新报道] Python DEBUG 小技巧

[复制链接]
发表于 2020-4-9 18:09:54 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 qiuyouzhi 于 2020-4-22 10:11 编辑

Python DEBUG 小技巧(1)


为什么要写这篇帖子?

因为论坛上的 "傻问题" 太多了!

光一个:

  1. list1 = [1,2,3,4,5]
  2. list2 = list1.reverse()
  3. print(list2)
复制代码


打印的结果为什么是None的问题,

就已经被问烂了!

本来,我试图搞一个Python FAQ,

结果发现根本没人看的。。。

(链接:https://fishc.com.cn/forum.php?m ... =view&ctid=1659

我和痛心,同时,还发现一大批看报错信息就能知道的问题,

却还要发帖询问为什么。

所以,这就是这篇帖子的由来。

学会看报错信息

假设有这么一段代码:

  1. print("Hello World!"
复制代码


大家是不是一眼就能看出来问题在哪里?

但是,如果改成这样:


  1. '''
  2. Function:
  3.         音乐下载器
  4. Author:
  5.         Charles
  6. 微信公众号:
  7.         Charles的皮卡丘
  8. '''
  9. import sys
  10. if __name__ == '__main__': from modules import *
  11. else: from .modules import *


  12. '''basic info'''
  13. BASICINFO = '''************************************************************
  14. Function: 音乐下载器 V2.1.2
  15. Author: Charles
  16. 微信公众号: Charles的皮卡丘
  17. 操作帮助:
  18.         输入r: 重新初始化程序(即返回主菜单)
  19.         输入q: 退出程序
  20.         下载多首歌曲: 选择想要下载的歌曲时,输入{1,2,5}可同时下载第1,2,5首歌
  21. 歌曲保存路径:
  22.         当前路径下的results文件夹内
  23. ************************************************************'''


  24. '''音乐下载器'''
  25. class musicdl():
  26.         def __init__(self, configpath=None, config=None, **kwargs):
  27.                 self.config = loadConfig('config.json') if config is None else config
  28.                 self.logger_handle = Logger(self.config['logfilepath'])
  29.                 self.initializeAllSources()
  30.         '''非开发人员外部调用'''
  31.         def run(self, target_srcs=None):
  32.                 while True:
  33.                         print(BASICINFO)
  34.                         # 音乐搜索
  35.                         user_input = self.dealInput('请输入歌曲搜索的关键词: ')
  36.                         target_srcs = ['baiduFlac', 'kugou', 'kuwo', 'qq', 'qianqian', 'netease', 'migu', 'xiami', 'joox'] if target_srcs is None else target_srcs
  37.                         search_results = self.search(user_input, target_srcs)
  38.                         # 打印搜索结果
  39.                         title = ['序号', '歌手', '歌名', '大小', '时长', '专辑', '来源']
  40.                         items = []
  41.                         records = {}
  42.                         idx = 0
  43.                         for key, values in search_results.items():
  44.                                 for value in values:
  45.                                         items.append([str(idx), value['singers'], value['songname'], value['filesize'], value['duration'], value['album'], value['source']])
  46.                                         records.update({str(idx): value})
  47.                                         idx += 1
  48.                         printTable(title, items)
  49.                         # 音乐下载
  50.                         user_input = self.dealInput('请输入想要下载的音乐编号: ')
  51.                         need_download_numbers = user_input.split(',')
  52.                         songinfos = []
  53.                         for item in need_download_numbers:
  54.                                 songinfo = records.get(item, '')
  55.                                 if songinfo: songinfos.append(songinfo)
  56.                         self.download(songinfos)
  57.         '''音乐搜索'''
  58.         def search(self, keyword, target_srcs):
  59.                 search_results = {}
  60.                 if 'baiduFlac' in target_srcs:
  61.                         try:
  62.                                 search_results.update({'baiduFlac': self.baiduFlac.search(keyword)})
  63.                         except:
  64.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('baiduFlac', keyword))
  65.                 if 'kugou' in target_srcs:
  66.                         try:
  67.                                 search_results.update({'kugou': self.kugou.search(keyword)})
  68.                         except:
  69.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('kugou', keyword))
  70.                 if 'kuwo' in target_srcs:
  71.                         try:
  72.                                 search_results.update({'kuwo': self.kuwo.search(keyword)})
  73.                         except:
  74.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('kuwo', keyword))
  75.                 if 'netease' in target_srcs:
  76.                         try:
  77.                                 search_results.update({'netease': self.netease.search(keyword)})
  78.                         except:
  79.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('netease', keyword))
  80.                 if 'qianqian' in target_srcs:
  81.                         try:
  82.                                 search_results.update({'qianqian': self.qianqian.search(keyword)})
  83.                         except:
  84.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('qianqian', keyword))
  85.                 if 'qq' in target_srcs:
  86.                         try:
  87.                                 search_results.update({'qq': self.qq.search(keyword)})
  88.                         except:
  89.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('qq', keyword))
  90.                 if 'migu' in target_srcs:
  91.                         try:
  92.                                 search_results.update({'migu': self.migu.search(keyword)})
  93.                         except:
  94.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('migu', keyword))
  95.                 if 'xiami' in target_srcs:
  96.                         try:
  97.                                 search_results.update({'xiami': self.xiami.search(keyword)})
  98.                         except:
  99.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('xiami', keyword))
  100.                 if 'joox' in target_srcs:
  101.                         try:
  102.                                 search_results.update({'joox': self.joox.search(keyword)})
  103.                         except:
  104.                                 self.logger_handle.warning('无法在%s中搜索 ——> %s...' % ('joox', keyword))
  105.                 return search_results
  106.         '''音乐下载'''
  107.         def download(self, songinfo):
  108.                 for songinfo in songinfos:
  109.                         if songinfo['source'] == 'baiduFlac':
  110.                                 self.baiduFlac.download([songinfo])
  111.                         elif songinfo['source'] == 'kugou':
  112.                                 self.kugou.download([songinfo])
  113.                         elif songinfo['source'] == 'kuwo':
  114.                                 self.kuwo.download([songinfo])
  115.                         elif songinfo['source'] == 'netease':
  116.                                 self.netease.download([songinfo])
  117.                         elif songinfo['source'] == 'qianqian':
  118.                                 self.qianqian.download([songinfo])
  119.                         elif songinfo['source'] == 'qq':
  120.                                 self.qq.download([songinfo])
  121.                         elif songinfo['source'] == 'migu':
  122.                                 self.migu.download([songinfo])
  123.                         elif songinfo['source'] == 'xiami':
  124.                                 self.xiami.download([songinfo])
  125.                         elif songinfo['source'] == 'joox':
  126.                                 self.joox.download([songinfo])




  127. '''run'''
  128. if __name__ == '__main__':
  129.         dl_client = musicdl('config.json')
  130.         dl_client.run()
复制代码

(感谢Charles未晞,这是TA的代码

这里由于篇幅问题,只展示部分代码)

你在不运行的情况下,是不是很难找到错误?
这时候,就体现报错信息的重要性了:

  1. Traceback (most recent call last):
  2.   File "C:\Users\rzzl\Desktop\Music-Downloader-master\Music-Downloader-master\musicdl\musicdl.py", line 158, in <module>
  3.     dl_client.run()
  4.   File "C:\Users\rzzl\Desktop\Music-Downloader-master\Music-Downloader-master\musicdl\musicdl.py", line 60, in run
  5.     self.download(songinfos)
  6.   File "C:\Users\rzzl\Desktop\Music-Downloader-master\Music-Downloader-master\musicdl\musicdl.py", line 112, in download
  7.     for songinfo in songinfos:
  8. NameError: name 'songinfos' is not defined
复制代码

(运行代码试试)

来分析报错信息:

1,看line,这是最有用的信息,它大多数都可以帮你定位到错误源。
2,看错误类型和错误信息,这是告诉你错误的详细内容。

可以发现,是112行的错误,直接翻到112:

  1. for songinfo in songinfos:
复制代码


发现这是整个函数的开头,于是错误就变得好找了很多,

songinfos是哪里来的呢?可以发现,是函数的一个参数。

  1. def download(self, songinfo):
复制代码


纳尼?这个参数怎么变成songinfo了?

赶紧改过来。

这时候再运行,发现没有问题了(这里鱼油

不需要自己尝试)。

这就是一次成功的DEBUG!

善用print()和DEBUG思想

有了print,你甚至可以不用调试功能!

(反正我是没有用过调试功能)

怎么做呢?

再拿一段代码例子:

  1. from requests import get
  2. from bs4 import BeautifulSoup as BS

  3. def open_url(url):
  4.     headers={'user-agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3741.400 QQBrowser/10.5.3863.400'}
  5.     res = get(url,headers=headers)
  6.     return res

  7. def get_MovieName(res):
  8.     soup = BS(res.text, "html.parser")
  9.     # 下面这段代码等同于soup.find_all()
  10.     target = soup("div", class_='p12')
  11.     for each in target:
  12.         print(each.a.span.text)

  13. def main():
  14.     url = 'https://movie.douban.com/chart'
  15.     res = open_url(url)
  16.     get_MovieName(res)

  17. if __name__ == "__main__":
  18.     main()
复制代码


运行一下:

诶嘿?怎么什么都没有打印出来?

理论上是可以的啊?

这时候,我们就要分析一下

有可能错误的原因:

1,get()能不能抓取到数据?
2,find_all方法的class_有没有写错?
3,确定打印的是each.a.span.text?

这时候,就需要我们的print()了:

打印一下返回的数据:

  1. print(res.text)
复制代码


OK,打印成功,大约有1600多行,

现在已经可以初步确定,get方法没有问题了。

但保险起见,还是展开看一下(防止是错误页面)

简单扫了扫,没有问题,证明这里是正确的。

然后看第二点,class_有没有写错?

翻源代码:

  1. <a class="nbg" href="https://movie.douban.com/subject/34805219/"  title="饥饿站台">
  2.                         <img src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2566870171.webp" width="75" alt="饥饿站台" class=""/>
  3.                     </a>
  4.             </td>

  5.             <td valign="top">
  6.                

  7.                 <div class="pl2">

  8.                     <a href="https://movie.douban.com/subject/34805219/"  class="">
  9.                         饥饿站台
  10.                         / <span style="font-size:13px;">饥饿斗室(港) / 绝命大平台(台)</span>
  11.                     </a>
复制代码


感觉并没有问题啊?

看看div的class,感觉是这里不对

把它复制过来:

我去,原来是pl(L)2,不是p12!

改过来之后,打印一下,成功了!

(第三点和第二点一起检查了)

3,打印所有错误类型

用这段代码:

  1. >>> for error in dir(__builtins__)[:72]:
  2.         print(error)
复制代码


4.try-except大法

这个东西可以捕获所有(貌似有一个错误捕获不到)的错误,

比如这里有一个爬虫程序,程序里面有一个for循环,

只要运行这个程序就会报错(索引超出范围),

这时我们怎么做呢?

直接把这个for循环放进try里面,然后except的时候

退出循环。

P.S:获取报错信息可以:
  1. except Errortype as reason:
复制代码


当然,如果你想获取任何错误的报错信息(By zltzlt):

  1. except BaseException as reason:
复制代码

评分

参与人数 3荣誉 +9 鱼币 +11 贡献 +9 收起 理由
liuzhengyuan + 2 + 3 + 3 有创意
LYF511 + 5 + 5 + 3 鱼C有你更精彩^_^
zltzlt + 2 + 3 + 3 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-4-9 18:47:19 | 显示全部楼层
没错~建议新手乐园发呀(他们只逛新手乐园,因为那里他们才能发帖)
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-30 13:16

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表