转载须注明出处:简书@Orca_J35 | GitHub@orca-j35

breakpoint() 是 Python 3.7 中新增加的内置函数,本文介绍了该函数的使用方法,目录结构如下:

5d3c52c5c2a2

目录.jpg

虽然 breakpoint 是由 C 语言实现的 ,但我们可以使用 Python pseudo-code 来描述其实现过程:

# In builtins.

def breakpoint(*args, **kws):

import sys

missing = object()

hook = getattr(sys, 'breakpointhook', missing)

if hook is missing:

raise RuntimeError('lost sys.breakpointhook')

return hook(*args, **kws)

# In sys.

def breakpointhook(*args, **kws):

import importlib, os, warnings

hookname = os.getenv('PYTHONBREAKPOINT')

if hookname is None or len(hookname) == 0:

hookname = 'pdb.set_trace'

elif hookname == '0':

return None

modname, dot, funcname = hookname.rpartition('.')

if dot == '':

modname = 'builtins'

try:

module = importlib.import_module(modname)

hook = getattr(module, funcname)

except:

warnings.warn(

'Ignoring unimportable $PYTHONBREAKPOINT: {}'.format(

hookname),

RuntimeWarning)

return hook(*args, **kws)

__breakpointhook__ = breakpointhook

2. how2 work

在未设置 PYTHONBREAKPOINT 的情况下,breakpoint() 会中断当前程序并进入 pdb 调试器。具体工作方式请查看相应子章节。

2.1 breakpoint()

breakpoint(*args, **kws)

伪代码:

# In builtins.

def breakpoint(*args, **kws):

import sys

missing = object()

# 设置钩子函数

hook = getattr(sys, 'breakpointhook', missing)

if hook is missing:

raise RuntimeError('lost sys.breakpointhook')

# 返回钩子函数的调用

return hook(*args, **kws)

可见 breakpoint 的工作仅是设置并调用 hook 函数,这里只需要注意以下几点:

breakpoint 中的 hook 变量将引用 sys.breakpointhook 函数对象;

breakpoint 会将自己所有的实参都传递给 sys.breakpointhook();

如果 sys.breakpointhook 缺失,则会抛出 RuntimeError

2.2 breakpointhook()

sys.breakpointhook(*args, **kws)

伪代码:

# In sys.

def breakpointhook(*args, **kws):

import importlib, os, warnings

hookname = os.getenv('PYTHONBREAKPOINT')

if hookname is None or len(hookname) == 0:

hookname = 'pdb.set_trace'

elif hookname == '0':

return None

modname, dot, funcname = hookname.rpartition('.')

if dot == '':

modname = 'builtins'

try:

# 模块导入失败,或funcname不可调用都会引发RuntimeWarning

module = importlib.import_module(modname)

hook = getattr(module, funcname)

except:

# 如果抛出异常,则不会执行hook(*args, **kws)

warnings.warn(

'Ignoring unimportable $PYTHONBREAKPOINT: {}'.format(

hookname),

RuntimeWarning)

# 如果实参与函数签名中的参数不匹配,则会抛出TypeError

return hook(*args, **kws)

__breakpointhook__ = breakpointhook

sys.breakpointhook 作为 breakpoint 的钩子函数,是正真实现具体功能的地方。

sys.breakpointhook 会访问环境变量 PYTHONBREAKPOINT,从而确定 hook 的引用对象,也就是说 PYTHONBREAKPOINT 的状态对执行结果有决定性的作用。

具体而言,PYTHONBREAKPOINT 存在如下几种状态:

完全不设置该环境变量:此时,hook 会引用 pdb.set_trace,所以最终会进入 pdb 调试器。(提示,由于 pdb.set_trace(*, header=None) 只接受关键字参数 header,因此不要向 breakpoint() 传递任何其它参数)

PYTHONBREAKPOINT=:此时,环境变量的值为空字符串,这与完全不设置该环境变量的效果相同。

PYTHONBREAKPOINT=0:此时,breakpointhook 会立即返回 None,从而禁用调试;

PYTHONBREAKPOINT=some.importable.callable:此时,breakpointhook() 将导入 some.importable 模块,然后通过 hook 引用模块中的 callable 对象

PYTHONBREAKPOINT=callable:此时,callable 表示一个内置可调用对象,如 PYTHONBREAKPOINT=print。

每次调用 sys.breakpointhook() 时,都会访问 PYTHONBREAKPOINT 变量。如果在程序执行期间改变了 PYTHONBREAKPOINT 的值, sys.breakpointhook() 便会读取变化后的值。因此,程序可以执行如下操作:

os.environ['PYTHONBREAKPOINT'] = 'foo.bar.baz'

breakpoint() # Imports foo.bar and calls foo.bar.baz()

注意:如果在解释器启动时伴随参数 -E,便会忽略所有 PYTHON* 环境变量(PYTHONBREAKPOINT 也不列外)。这意味着breakpoint() 会遵守默认行为,即中断当前程序并进入 pdb 调试器。

2.3 __breakpointhook__

# In sys.

__breakpointhook__ = breakpointhook

在初始化时 ,__breakpointhook__ 和 breakpointhook 会引用相同的函数对象。因此,就算重写了 breakpointhook 函数,也可通过 __breakpointhook__ 将其重置:

# 重置 breakpointhook

sys.breakpointhook = sys.__breakpointhook__

sys.breakpointhook / sys.__breakpointhook__ 工作方式与 sys.displayhook() / sys.__displayhook__ 和 sys.excepthook() / sys.__excepthook__ 完全相同。

3. with pdb.set_trace

在使用 pdb 调试器时,我们通常会这样设置断点:

def divide(e, f):

# 设置一个断点,执行至此处后,便会中断当前程序并进入pdb调试器。

import pdb; pdb.set_trace()

return f / e

在 Python 3.7 中,我们可以通过 breakpoint() 函数来设置断点(前提是未定义 PYTHONBREAKPOINT环境变量,或该环境变量的值等于空字符串)。

"""file_name:bugs.py"""

def divide(e, f):

breakpoint(header="进入调试器")

return e / f

a, b = 1, 9

print(divide(a, b))

此时,breakpointhook() 会返回 pdb.set_trace() ,从而进入 pdb 调试器。

Tips:在 Python 3.7 中,pdb.set_trace 仅支持关键字参数 header,不接受其他任何参数。如果传递了错误的参数,便会引发 TypeError 。

bugs.py 的执行效果如下:

$ python.exe bugs.py

进入调试器

> c:\users\iwhal\desktop\pytest\bugs.py(3)divide()

-> return e / f

(Pdb) p a+b

10

(Pdb) c

0.1111111111111111

Tips:命令 p 用于查看表达式的值;命令 c 用于退出调试器,并继续执行程序。

4. with pudb.set_trace

通过 PYTHONBREAKPOINT 还可选用别的调试器。例如,当我们想要使用 PuDB (一个基于控制台的可视化调试器)时,只需修改 PYTHONBREAKPOINT :

$ PYTHONBREAKPOINT=pudb.set_trace python3.7 bugs.py

注意:这里需要手动安装 pudb (pip install pudb),并且 pudb 仅支持类 UNIX 环境。由于我是 windows 环境,所以无法进行更详细的演示。

总之,通过修改PYTHONBREAKPOINT 的值,我们可以选择自己需要的调试器。但是同样需要注意的是:通过 breakpoint 传递的参数,是否与调试器的函数签名匹配。

5d3c52c5c2a2

pudb.png

5. with web_pdb.set_trace

如果想要使用 Web-PDB (Web-PDB 在内置 PDB 上增加了 web 界面,并允许在 web 浏览器中远程调试 Python 脚本),同样只需修改 PYTHONBREAKPOINT。注意:这里需要手动安装 web-pdb (pip install web-pdb)。

为了方便演示,先创建一个小脚本:

"""file_name:test.py"""

a, b = 1, 2

breakpoint()

a, b = b, a

修改 PYTHONBREAKPOINT ,并执行脚本:

$ PYTHONBREAKPOINT=web_pdb.set_trace python.exe test.py

2018-08-23 10:54:05,108: root - web_console:110 - CRITICAL - Web-PDB: starting web-server on LAPTOP-AR0R702R:5555...

之后便可通过浏览器,在 5555 端口上进入 Web-PDB 调试器:

5d3c52c5c2a2

web-pdb.jpg

6. with IPython.embed

breakpoint 函数不仅适用于调试器,也适用于任何可调用对象,只要参数匹配即可。因此,当我们想要在程序执行过程中,启动一个交互式 shell 时(比如 IPython),同样只需修改 PYTHONBREAKPOINT,如下:

$ PYTHONBREAKPOINT=IPython.embed python3.7 bugs.py

Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)]

Type 'copyright', 'credits' or 'license' for more information

IPython 6.5.0 -- An enhanced Interactive Python. Type '?' for help.

进入调试器

In [1]: a,b

Out[1]: (1, 9)

In [2]: quit()

0.1111111111111111

6.1 what's IPython.embed

IPython.embed(**kwargs) 会在程序的当前运行位置嵌入 IPython。在第一次调用该方法时,会先创建 InteractiveShellEmbed 类的一个实例,并调用该实例。再次调用该方法时,会直接调用之前创建的 InteractiveShellEmbed 实例。默认情况下,InteractiveShellEmbed 实例和当前程序使用相同的命名空间。另外,IPython.embed 允许我们在嵌入点打印指定字符串。

"""file_name:test.py"""

from IPython import embed

a = 10

b = 20

embed(header='First time')# 会在嵌入点打印该字符串

c = 30

d = 40

embed()

执行 test.py 脚本后,会分两次进入 IPython:

$ C:/Python37/python.exe c:/Users/iwhal/Desktop/PyTest/test.py

Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)]

Type 'copyright', 'credits' or 'license' for more information

IPython 6.5.0 -- An enhanced Interactive Python. Type '?' for help.

First time

In [1]: a,b

Out[1]: (10, 20)

In [2]: quit()

Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)]

Type 'copyright', 'credits' or 'license' for more information

IPython 6.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: a,b,c,d

Out[1]: (10, 20, 30, 40)

In [2]: quit()

7. with Functions

breakpoint 函数不仅适用于调试器,也适用于任何可调用对象。因此,我们可以通过 breakpoint 调用自定义函数,只要参数匹配即可。。

如下代码将创建一个可打印本地作用域内所有变量的函数:

"""file_name:bp_utils.py"""

from pprint import pprint

import sys

def print_locals(header=None):

print(header)

caller = sys._getframe(1) # Caller is 1 frame up.

pprint(caller.f_locals)

只要合理设置 PYTHONBREAKPOINT 便可调用该函数:

$ PYTHONBREAKPOINT=bp_utils.print_locals python.exe bugs.py

First time

{'e': 1, 'f': 9}

0.1111111111111111

基于同样的思路,我们还可以调用内置函数,比如 print 函数。

先创建一个脚本,用于向内置传递传输,只需包含 breakpoint 即可:

"""file_name:built_in.py"""

breakpoint("hello")

执行该脚本:

$ PYTHONBREAKPOINT=print python3.7 built_in.py

hello

7.1 what's sys._getframe

从调用栈(call stack)中返回一个帧(frame)对象。如果给出了 depth 参数(需是整数),则会返回栈顶下方对应深度的帧对象。如果 depth 值超过了调用栈的深度,将抛出 ValueError 异常。depth 的默认值是 0,此时会返回调用栈最顶部的帧。

CPython implementation detail: 该函数仅用于内部和专门用途。并不保证在所有 Python 实现中都存在。

8. 参考

python中breakpoint什么意思_breakpoint() Python 内置函数相关推荐

  1. Python中lambda详解(包括内置函数map、reduce、filter、sorted、max)

    文章目录 一.lambda是什么? 1.lambda语法 2.语法详解 二.lambda的使用 1.定义 2.调用 3.替换 4.作返回值 三.lambda作参数 1.map函数 2.reduce函数 ...

  2. Python中堪称神仙的六个内置函数

    人生苦短,菜鸟学Python! 今天,我们会一次性分享6个堪称神仙的内置函数.在很多计算机书籍中,它们也通常作为高阶函数来介绍.而我自己在日常工作中,经常使用它们来使代码更快,更易于理解. Lambd ...

  3. Python 中堪称神仙的6个内置函数

    大家好,之前给大家分享过3个节省时间的Python技巧,当时就提出了,建议大家多使用Python的内置函数,既能提高自己的Python程序速度,同时还能保持代码简洁易懂. 今天,我会一次性分享6个堪称 ...

  4. python中的True和False以及内置函数any()、all()

    文章目录 1.内置函数all().any() 2.python中哪些元素是真True,哪些元素是假False 3.python中的None对象 4.python中的布尔(bool)值 5.内置函数al ...

  5. python中reversed是什么意思_Python内置函数reversed()用法分析

    这篇文章主要介绍了Python内置函数reversed()用法,结合实例形式分析了reversed()函数的功能及针对序列元素相关操作技巧与使用注意事项,需要的朋友可以参考下 reversed()函数 ...

  6. Python中几个操作列表的内置函数filter(),map(),reduce(),lambda

    Python内置了一些非常有趣但非常有用的函数,充分体现了Python的语言魅力! filter(function, sequence):对sequence中的item依次执行function(ite ...

  7. python中reversed是什么意思_python 内置函数 reversed()

    reversed()函数是返回序列seq的反向访问的迭代子.参数可以是列表,元组,字符串,不改变原对象. 1>参数是列表 >>> l=[1,2,3,4,5] >>& ...

  8. [转载] Python列表排序 list.sort方法和内置函数sorted

    参考链接: Python中的函数 Python列表排序 list.sort方法和内置函数sorted 很多时候我们获取到一个列表后,这个列表并不满足我们的需求,我们需要的是一个有特殊顺序的列表. 这时 ...

  9. Python列表排序 list.sort方法和内置函数sorted

    Python列表排序 list.sort方法和内置函数sorted 很多时候我们获取到一个列表后,这个列表并不满足我们的需求,我们需要的是一个有特殊顺序的列表. 这时候就可以使用list.sort方法 ...

最新文章

  1. 格式化代码会发生什么?? | 每日趣闻
  2. 两个函数式解决大数相加的方法
  3. Handler为什么可能会造成内存泄漏以及可用的四种解决方法
  4. 5、ShardingSphere 之 公共表
  5. AD20学习笔记5---PCB设计规则设置及PCB手工布线
  6. EFCore废弃了TransactionScope取而代之的Context.Database.BeginTransaction
  7. 中怎么撤回消息_微信消息撤回也能看到,这个开源神器牛x!语音、图片、文字都支持!...
  8. 批量 材质 调整_寒霜引擎的PBR实践3.0(一)材质篇
  9. 如何修改Windows 7登录界面默认输入法?
  10. ios--小结系列三
  11. jsp+aJax 登陆成功
  12. Android将应用log信息保存文件
  13. 波音可以自己做安全认证,错误在于故意掩盖问题
  14. ios安卓模拟器_雷电模拟器4.0.5去广告修改版
  15. android rom定制 电视盒子,开发电视盒子的极简Android TV桌面
  16. INT 10H中断功能详解
  17. NIOSII 安装问题汇总
  18. 微信公众开发 表情开发php,微信公众帐号开发教程第9篇-QQ表情的发送与接收_PHP教程...
  19. 创业公司的抗争,共享单车的合并
  20. Freeswitch服务+语音网关设备发送短信功能

热门文章

  1. 58同城2021校招笔试真题-前端
  2. 明星热图|欧阳娜娜、张艺兴代言新品牌;吴彦祖、高圆圆、全智贤演绎服装新品;关晓彤、欧阳靖、张云龙出席品牌活动...
  3. Visual Studio 2010 Power Tool
  4. JavaScript/HTML格式化
  5. c语言程序设计陈世清上海交通大学出版社,C语言程序设计
  6. obs 推流编码在哪设置_直播软件OBS推流的设置方法
  7. yoast seo_Yoast SEO vs All in a SEO Pack –最好的WordPress SEO插件是哪个?
  8. 复旦大学2020计算机考试大纲,复旦大学2020年硕士研究生招生考试自命题科目考试大纲-761卫生综合(一)大纲...
  9. ubuntu系统构建VNC虚拟远程桌面
  10. 互联网寒冬!docker安装nacos集群