我的编程空间,编程开发者的网络收藏夹
学习永远不晚

#6 ipdb模块源代码解读

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

#6 ipdb模块源代码解读

前言

好久不见,大家最近可好?。通过前几节的学习,相信你已经掌握了面向对象的大量知识,但是光知道是不够的,需要自己多写、多看,学一门语言无非不过这两种秘诀嘛。因此本篇博文带着大家剖析一次源代码,剖析对象为代码调试模块:ipdb。为什么选择这个模块呢?因为下一次的博文计划写Python代码调试的啦~~Go!!!

一、ipdb介绍

1.1 ipdb介绍

ipdb是一款调试代码的第三方模块

我想这一句话就给出了ipdb的所有信息了哇

1.2 ipdb安装

既然是第三方模块,那么就需要自己来安装,使用pip即可,在命令行输入:

pip install ipdb

测试安装是否成功,在命令行输入:

python -m ipdb

如果安装成功则会输出以下内容:

usage: python -m ipdb [-c command] ... pyfile [arg] ...

Debug the Python program given by pyfile.

Initial commands are read from .pdbrc files in your home directory
and in the current directory, if they exist.  Commands supplied with
-c are executed after commands from .pdbrc files.

To let the script run until an exception occurs, use "-c continue".
To let the script run up to a given line X in the debugged file, use
"-c 'until X'"
ipdb version 0.10.3.

如果安装失败请重新pip安装或者换用其他方法,之前介绍过,这里就不列举了

二、源代码剖析

2.1 源代码位置

想要剖析这一个模块,首先应该找到源代码的位置,由于模块是由pip安装的,所以可以使用pip查看模块的详细信息,在命令行中输入:

pip show ipdb

输出的详细信息中,有一行Location信息,每个人的位置可能不同,以自己的为准,这里输出我自己的位置:

Location: /Users/minutesheep/.pyenv/versions/3.5.2/Python.framework/Versions/3.5/lib/python3.5/site-packages

进入上面?所示的目录中,会发现site-packages目录里有许多模块,ipdb模块的源代码有两个,一个是 ipdb ,另一个是 ipdb-0.11-py3.5.egg-info 

2.2 源代码文件剖析

如果你仔细观察的话,你会发现每一个模块基本是都是两个文件夹,一个文件夹是模块本身,另一个是以info结尾的文件夹,下面以ipdb模块讲解:

ipdb 文件夹

这个文件夹里面存放着ipdb模块的源代码,里面有

 __init__.py    __main__.py  

 __pycache__    stdout.py

ipdb-0.11-py3.5.egg-info 文件夹

从名称上就可以看出这是一个存放信息的文件夹,里面有 

PKG-INFO   dependency_links.txt  installed-files.txt  

top_level.txt  SOURCES.txt   entry_points.txt   requires.txt   zip-safe

PKG-INFO:内容是模块的信息,包括模块名、版本、依赖、作者、代码地址、许可、描述、历史版本变更信息

dependency_links.txt:内容是依赖模块链接

installed-files.txt:内容是安装这个模块时安装的文件

top_level.txt:内容是父亲模块

SOURCES.TXT:内容是整个模块所有的文件

entry_points.txt:内容是程序入口语句

requires.txt:本模块需要的其他模块

zip-safe:这个文件我也不清楚?

『防抄袭:读者请忽略这段文字,文章作者是博客园的MinuteSheep』

2.3 源代码剖析

__init__.py

 1 # Copyright (c) 2007-2016 Godefroid Chapelle and ipdb development team
 2 #
 3 # This file is part of ipdb.
 4 # Redistributable under the revised BSD license
 5 # https://opensource.org/licenses/BSD-3-Clause
 6 
 7 from ipdb.__main__ import set_trace, post_mortem, pm, run             # noqa
 8 from ipdb.__main__ import runcall, runeval, launch_ipdb_on_exception  # noqa
 9 
10 from ipdb.stdout import sset_trace, spost_mortem, spm                 # noqa
11 from ipdb.stdout import slaunch_ipdb_on_exception                     # noqa

__init__.py到底是个什么文件呢?为什么Python项目中总是会出现这个诡异的文件呢?

__init__.py其实是将这个文件夹变成一个Python模块,方便以后导入。

每当我们使用import语句时,其实导入的就是这个模块的__init__.py文件。

通常一个模块的许多方法并不会写在同一个文件中,而是会有分类的写入不同的文件中,最后将这个模块的所有方法都一次性写入__init__.py文件中(相当于为所有方法提供一个公共接口),导入的时候将会方便许多。

本模块的__init__.py文件中,前5行是注释信息,这里就不翻译了;第7行开始,进入正式代码,可以看到从__main__.py文件中导入了许多种方法,之后又从stdout.py中导入了许多方法

 

__main__.py

这个文件就是整个模块的主程序了,源代码就放在这个文件中

  1 # Copyright (c) 2011-2016 Godefroid Chapelle and ipdb development team
  2 #
  3 # This file is part of ipdb.
  4 # Redistributable under the revised BSD license
  5 # https://opensource.org/licenses/BSD-3-Clause
  6 
  7 
  8 from IPython.terminal.embed import InteractiveShellEmbed
  9 from IPython.terminal.ipapp import TerminalIPythonApp
 10 from IPython.core.debugger import BdbQuit_excepthook
 11 from IPython import get_ipython
 12 import os
 13 import sys
 14 
 15 from contextlib import contextmanager
 16 
 17 __version__ = "0.10.3"
 18 
 19 
 20 shell = get_ipython()
 21 if shell is None:
 22     # Not inside IPython
 23     # Build a terminal app in order to force ipython to load the
 24     # configuration
 25     ipapp = TerminalIPythonApp()
 26     # Avoid output (banner, prints)
 27     ipapp.interact = False
 28     ipapp.initialize([])
 29     shell = ipapp.shell
 30 else:
 31     # Running inside IPython
 32 
 33     # Detect if embed shell or not and display a message
 34     if isinstance(shell, InteractiveShellEmbed):
 35         sys.stderr.write(
 36             "\nYou are currently into an embedded ipython shell,\n"
 37             "the configuration will not be loaded.\n\n"
 38         )
 39 
 40 # Let IPython decide about which debugger class to use
 41 # This is especially important for tools that fiddle with stdout
 42 debugger_cls = shell.debugger_cls
 43 def_colors = shell.colors
 44 
 45 
 46 def _init_pdb(context=3, commands=[]):
 47     try:
 48         p = debugger_cls(def_colors, context=context)
 49     except TypeError:
 50         p = debugger_cls(def_colors)
 51     p.rcLines.extend(commands)
 52     return p
 53 
 54 
 55 def wrap_sys_excepthook():
 56     # make sure we wrap it only once or we would end up with a cycle
 57     #  BdbQuit_excepthook.excepthook_ori == BdbQuit_excepthook
 58     if sys.excepthook != BdbQuit_excepthook:
 59         BdbQuit_excepthook.excepthook_ori = sys.excepthook
 60         sys.excepthook = BdbQuit_excepthook
 61 
 62 
 63 def set_trace(frame=None, context=3):
 64     wrap_sys_excepthook()
 65     if frame is None:
 66         frame = sys._getframe().f_back
 67     p = _init_pdb(context).set_trace(frame)
 68     if p and hasattr(p, 'shell'):
 69         p.shell.restore_sys_module_state()
 70 
 71 
 72 def post_mortem(tb=None):
 73     wrap_sys_excepthook()
 74     p = _init_pdb()
 75     p.reset()
 76     if tb is None:
 77         # sys.exc_info() returns (type, value, traceback) if an exception is
 78         # being handled, otherwise it returns None
 79         tb = sys.exc_info()[2]
 80     if tb:
 81         p.interaction(None, tb)
 82 
 83 
 84 def pm():
 85     post_mortem(sys.last_traceback)
 86 
 87 
 88 def run(statement, globals=None, locals=None):
 89     _init_pdb().run(statement, globals, locals)
 90 
 91 
 92 def runcall(*args, **kwargs):
 93     return _init_pdb().runcall(*args, **kwargs)
 94 
 95 
 96 def runeval(expression, globals=None, locals=None):
 97     return _init_pdb().runeval(expression, globals, locals)
 98 
 99 
100 @contextmanager
101 def launch_ipdb_on_exception():
102     try:
103         yield
104     except Exception:
105         e, m, tb = sys.exc_info()
106         print(m.__repr__(), file=sys.stderr)
107         post_mortem(tb)
108     finally:
109         pass
110 
111 
112 _usage = """\
113 usage: python -m ipdb [-c command] ... pyfile [arg] ...
114 
115 Debug the Python program given by pyfile.
116 
117 Initial commands are read from .pdbrc files in your home directory
118 and in the current directory, if they exist.  Commands supplied with
119 -c are executed after commands from .pdbrc files.
120 
121 To let the script run until an exception occurs, use "-c continue".
122 To let the script run up to a given line X in the debugged file, use
123 "-c 'until X'"
124 ipdb version %s.""" % __version__
125 
126 
127 def main():
128     import traceback
129     import sys
130     import getopt
131 
132     try:
133         from pdb import Restart
134     except ImportError:
135         class Restart(Exception):
136             pass
137 
138     opts, args = getopt.getopt(sys.argv[1:], 'hc:', ['--help', '--command='])
139 
140     if not args:
141         print(_usage)
142         sys.exit(2)
143 
144     commands = []
145     for opt, optarg in opts:
146         if opt in ['-h', '--help']:
147             print(_usage)
148             sys.exit()
149         elif opt in ['-c', '--command']:
150             commands.append(optarg)
151 
152     mainpyfile = args[0]     # Get script filename
153     if not os.path.exists(mainpyfile):
154         print('Error:', mainpyfile, 'does not exist')
155         sys.exit(1)
156 
157     sys.argv = args     # Hide "pdb.py" from argument list
158 
159     # Replace pdb's dir with script's dir in front of module search path.
160     sys.path[0] = os.path.dirname(mainpyfile)
161 
162     # Note on saving/restoring sys.argv: it's a good idea when sys.argv was
163     # modified by the script being debugged. It's a bad idea when it was
164     # changed by the user from the command line. There is a "restart" command
165     # which allows explicit specification of command line arguments.
166     pdb = _init_pdb(commands=commands)
167     while 1:
168         try:
169             pdb._runscript(mainpyfile)
170             if pdb._user_requested_quit:
171                 break
172             print("The program finished and will be restarted")
173         except Restart:
174             print("Restarting", mainpyfile, "with arguments:")
175             print("\t" + " ".join(sys.argv[1:]))
176         except SystemExit:
177             # In most cases SystemExit does not warrant a post-mortem session.
178             print("The program exited via sys.exit(). Exit status: ", end='')
179             print(sys.exc_info()[1])
180         except:
181             traceback.print_exc()
182             print("Uncaught exception. Entering post mortem debugging")
183             print("Running 'cont' or 'step' will restart the program")
184             t = sys.exc_info()[2]
185             pdb.interaction(None, t)
186             print("Post mortem debugger finished. The " + mainpyfile +
187                   " will be restarted")
188 
189 
190 if __name__ == '__main__':
191     main()

一下子看到这么长的代码是不是蒙圈了?,遇到这种长的代码,第一步就是在心理上战胜自己!要想成长,就要多看这种标准代码,学习代码思想,模仿代码风格,这样一步一步脚踏实地走下去,你自己写出这样优秀的代码指日可待!

拿到这么长的代码,先大致浏览一下:

1-5行;注释信息;8-15行:导入模块;17行:定义版本变量;20-43行:运行一小段程序(通常是程序的配置);46-109行:定义若干函数;112-124行:定义字符串变量;127-187行:main函数;190-191:判断主程序并运行

通过上面这种方法将程序分解掉,整个程序一下子清晰明了,瞬间感觉so easy~~~

来跟着我稍微详细的走一遍整个程序的运行过程(具体的内容就不做介绍了,因为许多内容需要详细的掌握IPython):

1.从IPthon导入四种方法,导入os和sys模块,从contextlib导入contextmanager(这是一个装饰器)

2.定义当前版本为:0.10.3

3.获得一个ipython的shell环境

4.判断这个shell是否存在:如果不存在,强制性的创建一个ipython环境;如果存在,则检测其是否为InteractiveShellEmbed的一个对象,如果是,则输出标准错误语句“You are currently into an embedded ipython shell""the configuration will not be loaded."

5.使用当前IPython的主题和颜色

6.执行第112行语句,定义_usage字符串

7.执行第190行语句,判断是否为__main__,是的话运行main函数

8.执行127行语句,运行main函数

9..........

以上就是稍微详细的运行过程,感兴趣的小伙伴可以继续深入到每一步是如何运行的,由于篇幅关系,我就不再深入了。

 

stdout.py

 1 import sys
 2 from contextlib import contextmanager
 3 from IPython.utils import io
 4 from .__main__ import set_trace
 5 from .__main__ import post_mortem
 6 
 7 
 8 def update_stdout():
 9     # setup stdout to ensure output is available with nose
10     io.stdout = sys.stdout = sys.__stdout__
11 
12 
13 def sset_trace(frame=None, context=3):
14     update_stdout()
15     if frame is None:
16         frame = sys._getframe().f_back
17     set_trace(frame, context)
18 
19 
20 def spost_mortem(tb=None):
21     update_stdout()
22     post_mortem(tb)
23 
24 
25 def spm():
26     spost_mortem(sys.last_traceback)
27 
28 
29 @contextmanager
30 def slaunch_ipdb_on_exception():
31     try:
32         yield
33     except Exception:
34         e, m, tb = sys.exc_info()
35         print(m.__repr__(), file=sys.stderr)
36         spost_mortem(tb)
37     finally:
38         pass

这个文件是ipdb模块的另一个文件,编写项目时,不会将所有方法都写入同一个文件中的,而是将不同的方法分类放入不同的文件中,这个文件的内容就不做详细讲解了。

 

__pycache__

这是一个文件夹,里面存放着许多以.pyc结尾的文件,这些文件时什么呢?

其实从文件夹的名称就可以看出这些是缓存文件。

Python程序为了加快程序的运行速度,在第一次导入模块后,会在本模块目录中生成__pycache__的缓存文件夹,里面存放着编译过的文件;下一次再次导入这个模块时,直接执行pyc文件,大大加快了程序的运行速度;每当模块里的py文件的修改时间发生变化时,就会重新生成pyc文件。

 

结语

以上就是ipdb模块源代码的剖析,相信你已经有了分析源代码的能力了!下一篇博文将会记录Python是如何调试代码(debug)的,下次见!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

#6 ipdb模块源代码解读

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

#6 ipdb模块源代码解读

前言好久不见,大家最近可好?。通过前几节的学习,相信你已经掌握了面向对象的大量知识,但是光知道是不够的,需要自己多写、多看,学一门语言无非不过这两种秘诀嘛。因此本篇博文带着大家剖析一次源代码,剖析对象为代码调试模块:ipdb。为什么选择这
2023-01-30

StoneDB 源码解读系列查询模块流程及源码介绍

StoneDB 是一个高性能、可扩展的分布式存储系统,具有强一致性、高可用性和持久性特性。其中查询模块是 StoneDB 的核心组件之一,负责处理用户的查询请求并返回相应的结果。查询模块的流程大致如下:1. 接收查询请求:查询模块首先接收用
2023-09-21

Python3 Random模块代码详解

描述random() 方法返回随机生成的一个实数,它在[0,1)范围内。import random help(random) FUNCTIONSbetavariate(alpha, beta) method of Random instan
2022-06-04

Spring中MVC模块代码详解

SpringMVC的Controller用于处理用户的请求。Controller相当于Struts1里的Action,他们的实现机制、运行原理都类似Controller是个接口,一般直接继承AbstrcatController,并实现han
2023-05-30

Spring之ORM模块代码详解

Spring框架七大模块简单介绍Spring中MVC模块代码详解ORM模块对Hibernate、JDO、TopLinkiBatis等ORM框架提供支持ORM模块依赖于dom4j.jar、antlr.jar等包在Spring里,Hiberna
2023-05-30

vue3模块创建runtime-dom源码解析

这篇文章主要为大家介绍了vue3模块创建runtime-dom源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-12

JavaScript 模块化密码学家:破解模块化编程的代码

JavaScript 模块化编程极大地增强了代码的可维护性和可重用性。本文深入探讨模块化编程的技术和最佳实践,提供实用示例,帮助您破解模块化编程代码的复杂性。
JavaScript 模块化密码学家:破解模块化编程的代码
2024-02-18

聊聊Vue3 shared模块下38个工具函数(源码阅读)

Vue3的工具函数对比于Vue2的工具函数变化还是很大的,个人感觉主要还是体现在语法上,已经全面拥抱es6了; 对比于工具类的功能变化并没有多少,大多数基本上都是一样的,只是语法上和实现上有略微的区别。
2023-05-14

JavaScript 模块化解密:从零开始构建模块化代码

JavaScript 模块化是组织和管理代码的强大技术。通过将代码分解成较小的、可重用的模块,可以增强代码的可读性、可维护性,并且在团队协作时避免冲突。
JavaScript 模块化解密:从零开始构建模块化代码
2024-02-18

python如何使用typing模块加强代码的可读性

这篇文章主要为大家展示了“python如何使用typing模块加强代码的可读性”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“python如何使用typing模块加强代码的可读性”这篇文章吧。一、
2023-06-22

单独编译Android 源代码中的模块实现方法

第一次下载好Android源代码工程后,我们通常是在Android源代码工程目录下执行make命令,经过漫长的等待之后,就可以得到Android系统镜像system.img了。以后如果我们修改了Android源代码中的某个模块或
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录