代码调试
问题阐述
最近遇到一个python debug多进程的问题
有一个进程A,这个进程会fork出8个进程B,fork join结束后,又会fork出8个进程A。
假设按时间有序,我就只想断fork出的第一个B和第一个进程A,怎么做?(breakpoint just break only once)
类似于java多线程调试的意思,只断一个线程,all->thread,make default
断点命中时不会阻塞其他进程
https://blog.csdn.net/u011781521/article/details/79251819
主要几个问题点
- 多个进程会同时刷log,特别乱,没办法过滤(加pid过滤,还算好解决)
- 使用pdb断点时,会同时block所有其他进程
调试主流方式
首先python主流有两类debug方式
第一类是通过ide,比如vscode、pycharm。
比较无脑、界面化的操作方式,但缺点也很明显,很依赖一个可以控制的函数入口(例如main,ut入口)。
第二类是通过pdb,在相关代码片段中加breakpoint语句,等进程执行时自动触发断点,进行拦截。
适合一些比较复杂的进程衍生模式,不太依赖特定的函数入口。这种相对来说更精确一点,对依赖外部环境依赖小。
需要对pdb、gdb类似的东西有一定的了解。其次,多进程下并不太友好;pdb本身功能过于单一。
找了一下pdb的平替有pdb++、ipdb、rpdb。
rpdb就是remote,前两个其实差不多,但是pdb的好处是,基本你不需要去改原来的pdb断点,开箱即用。
pdb++还有啥好处见引文,但是还是存在多进程不友好的问题,会多次触发断点,一个命令语句会有较多的副作用,尤其在Smart command parsing加持下,基本就是不可调试的状态。
TL; DR
pdbpp
(又称pdb++
)是 Python 标准调试器pdb
的一个增强版本,为调试体验提供了许多改进和新功能。在功能上,它完全向后兼容pdb
,但增加了许多便利的特性,简化了调试过程。以下是pdbpp
相比于pdb
提供的主要增强功能:1. 彩色语法高亮(Syntax Highlighting)
pdbpp
使用pygments
库为代码和输出提供彩色语法高亮显示,使得调试器输出更加易读,特别是在查看复杂表达式和代码块时。变量名、关键字、字符串、数字等会有不同的颜色,帮助用户快速定位信息。
- pdb:没有颜色,输出是纯文本。
- pdbpp:提供语法高亮,颜色区分不同类型的内容。
2. 更强大的自动补全(Tab Completion)
在
pdbpp
中,按下Tab
键可以自动补全变量名、函数名、类名等,类似于现代 IDE 中的补全功能。这大大提高了调试时的效率,特别是在处理复杂的对象或长命名时。
- pdb:有限的自动补全功能。
- pdbpp:增强的自动补全,支持更多命令、变量、对象属性和方法。
3. 可配置的显示选项(Sticky Mode)
pdbpp
提供一个非常强大的 "sticky mode",它可以在调试过程中始终显示当前代码的上下文。每次执行下一步时,pdbpp
会自动刷新并显示当前代码段的最新状态,而不需要手动查看代码上下文。
- pdb:手动使用
list
或longlist
查看代码上下文。- pdbpp:
sticky mode
持续显示代码上下文,用户更容易跟踪执行的代码。4. 更智能的调试命令
pdbpp
增强了原始pdb
的一些常用命令,并增加了新的命令:
interact
:允许你在调试器中启动一个交互式 Python shell,直接操作调试时的上下文和变量。longlist
(ll
):显示当前函数的完整代码,而不仅仅是当前行的上下文。sticky
:启用或禁用sticky mode
,在该模式下会持续显示代码的上下文。track
:跟踪异常,并显示其完整的追溯信息。source
:查看某个函数或方法的完整源代码。5. 更灵活的配置和扩展
pdbpp
提供了更多的配置选项,允许你通过.pdbrc
文件自定义调试器的行为,例如颜色、补全方式、命令别名等。
- pdb:有限的配置选项。
- pdbpp:支持用户自定义配置文件,灵活设置调试器的行为。
6. 更好的 Python 3 支持
pdbpp
针对 Python 3 做了更多优化,支持 Python 3 的新语法和特性,如async
和await
,并能更好地处理 Python 3 中的一些新特性。7. 友好的错误信息
pdbpp
提供了更加直观的错误信息格式,增强了显示异常和回溯的方式,使调试复杂的错误更加容易。8. 可自定义的调试器提示符
你可以通过
pdbpp
自定义调试器的提示符(prompt)。这对某些开发者来说是个很方便的功能,特别是当你在长时间调试时,能够清楚知道当前的调试状态。9. 显示变量值的悬停功能
当你在
pdbpp
中查看代码时,悬停在变量上会显示其当前的值。这对于快速查看变量的状态非常有用,无需输入变量名来查看当前值。
小结
pdbpp
是pdb
的一个增强版本,带来了彩色高亮、自动补全、sticky mode
、自定义配置等功能,大大提升了调试体验。如果你经常使用pdb
进行调试,pdbpp
将让你的调试过程更高效、愉快。
问题场景
现在我往我关心的代码里,加入了断点import pdb; pdb.set_trace()
,但是他连续触发了8次,导致我没办法继续调试了,怎么办?
按了一次c直接所有其他进程都相应,我有没有办法只断某一个进程(随便哪个)?
比较直觉的会想到条件断点,但是触发条件的唯一值有哪些呢?
方案思路
天然唯一值,比如pid、ppid、deviceid、特定配置参数,process相关参数,持有的一些特殊资源(fd描述符)。
非天然唯一值,比如特定环境变量。
也可以考虑锁,谁先抢占到锁,谁就一直持有这把锁(至少能保证只有一个进程断到),这个可以往一个特定文件写入pid实现。封装一个get函数,这个函数尝试读取一个文件,如果这个文件不存在,先创建并写入当前的进程id,再返回该id,如果这个文件存在,直接返回文件内容转成int,上层只需要比较id和自身os.getpid()的一致性。
方案细节
方案A 判断ppid
由于最开始只有一个父进程,所以用他作为ppid去判定。然而并不正确,子进程fork了8个,8个同时命中无效。
方案B 判断pid
pid对10取余,用一个magic number(比如0),判断相等性,进行断点。
(有效且粗暴的方式,但具有一定随机性。这块是由于进程pid的分配算法,进程pid并不一定具有连续性,并且有一定随机性,有可能出现无法命中或者多次命中的概率。)
方案C 父进程传变量给子进程
只需要在子进程fork一开始传入一个唯一值即可,这里用到了环境变量。
首先最开始的父进程A进程是一个前台进程,ctrl+c打断时,会触发一些multiprocessing和task相关的堆栈,其实可能A在执行过程中fork了其他所有进程(事实上并不对)。
尝试检索了一下相关库,检索multiprocessing关键字,确实能找到一句
ctx = multiprocessing.get_context("spawn")
...
for i in range(5):item = ctx.Process(...)item.start()
...
尝试在loop中,先设置os.environ['DEBUG']=i
,fork出来的子进程会继承(unix机制,子进程会继承父进程的一些属性)环境变量,尝试用该环境变量做判断,发现断点断不上,这个方案是有问题的。
原因是父进程A fork出了8个B,我们关心的断点其实在B的进程中,fork完8个B进程,父进程A完成join,继续开始fork8个A子进程,理论上这些断点会生效,但是我们miss掉了断点出现的时机。
方案D 父进程B读取一些特定配置值(比如deviceid 0-8)做判断
D.A 尝试读取一个config值里的特定字段,但发现这个config是动态生成的,他也不是一个单例(python中的单例不太一样,强行弄意义不大),并且这个值加载的时机不明确,所以不能用
D.B 尝试获取该进程持有的一些资源、文件描述符(如/dev/xxx),感觉有点麻烦,但是理论上是可行的
D.C 通过ps -ef
观察,其实进程B在启动时有一些特定的唯一值入参,进程的启动命令大概长process_b device_id 8 deivce_id xxxx
,能明显看出,第二个参数就是我们需要的唯一值。
尝试通过sys.argv获取第一个参数,直接判断。发现sys.argv竟然是空的,那么这些参数来自哪里呢?
只有通过python命令行启动的进程,才会有sys.argv,如果不是这种方式,比如用c启动的命令行,他就不会有这个参数。
那如何获取这个参数?
两种方式,第一种取读取/proc/{pid}/cmdline
下的一些属性,找到这个值,第二种
import psutil
p = psutil.Process()
cmdline = p.cmdline()
采用了第二种方式,再pdb++获取了cmdline[1],并且和'1'比较测试了一下,是成功的。至此,完成了条件断点。
小结
- 要注意观察进程的创建方式和创建的流程(ps -ef, pstree)
- 明确需要断点问题的界限
- 寻找一切与问题相关的上下文,尽可能将问题缩小在一个区间
TL;DR
代码阅读&修改
container内python代码调试
现在的ide普遍都支持ssh连接,理论上只要配置好了ssh服务,就可以直接连container,直接对container内的代码进行调试。(直接用开发机的开发机环境是最好的,代码可以随意点,都不会报错和飘红)
ssh
安装ssh服务(能用apt直接安的可以省这一步)
- 从网站随意下一下源码包
https://www.openssh.com/portable.html
- 解压进入到代码目录
- ./configure 生成编译需要的配置文件
- make $(nproc) 编译
- make install 安装
配置
vim /etc/sshd/sshd_config
PermitRootLogin改成yes,password-auth也改成yes,端口随便换一个,不要和宿主机撞
启动
service ssh start
(这块不能用systemctl)
宿主机要把docker这个端口主动的暴露出去(这个在启动的时候就要完成)
pycharm ssh配置连接
包太大,下载不了的问题参考
https://blog.csdn.net/qq_42534403/article/details/135969955
连接完效果大概像
基本和本地开发效果一致,比较恼火的是,他有时候不会保存项目打开前后的上下文,可能你做的一些mark或者pin都会丢失。
如果对library进行调试,额外注意需要标注
pdb++ cheatsheet (via gpt4)
个人感觉比较好用的就是ll pp sticky,最好禁用Smart command parsing(真是自作聪明的行为),基本用着和解释性语言的感觉差不多,像是直接在python中运行一样
下面是一个方便参考的
pdb++
调试命令 Cheatsheet,它包含了pdb++
中常用的调试命令以及增强功能,帮助你快速上手调试。
pdb++ Cheatsheet
基本命令
命令 说明 h
/help
显示帮助信息,输入 help <command>
查看某个命令的详细帮助。n
/next
执行下一行代码,跳过函数调用。 s
/step
进入下一行代码,如果是函数调用,则进入函数内部。 r
/return
执行到当前函数的返回处。 c
/continue
继续执行程序,直到遇到下一个断点。 q
/quit
退出调试器,终止程序。 l
/list
显示当前代码的上下文(默认 11 行),可指定范围,如 list 10, 20
。ll
/longlist
显示当前函数的完整代码。 p
/打印表达式的值,例如 p my_var
。pp
使用漂亮的格式(pretty print)打印表达式的值。 w
/where
显示当前的调用栈信息。 bt
同 where
,显示完整的回溯信息。up
/u
移动到上一层调用栈。 down
/d
移动到下一层调用栈。
断点管理
命令 说明 b
/break
设置断点。用法: break <lineno>
或break <filename>:<lineno>
。tbreak
设置临时断点,命中一次后自动删除。 cl
/clear
清除所有断点。 disable
禁用断点。 enable
启用断点。 ignore
忽略断点,指定命中多少次后才激活。 condition
为断点设置条件。例如: condition 1 x > 10
。
变量和表达式
命令 说明 p
/打印表达式的值,例如 p my_var
。pp
使用漂亮的格式(pretty print)打印表达式的值。 whatis
显示表达式的类型,例如 whatis my_var
。display
每次停止时自动显示一个表达式的值,例如 display my_var
。undisplay
取消显示某个表达式的值。 a
/args
打印当前函数的参数及其值。 retval
显示最后一个返回值。 locals()
查看当前作用域中的局部变量。 globals()
查看全局变量。
代码执行
命令 说明 !
执行 Python 表达式。例如 !my_var = 5
。interact
启动一个交互式 Python shell,可以在当前上下文中执行任意代码。 run
重新运行脚本。例如: run arg1 arg2
。
特殊功能
命令 说明 sticky
启用/禁用 粘性模式,在调试时持续显示代码上下文。 source
显示某个函数或类的源代码,例如 source my_function
。track
跟踪异常,显示其完整的追溯信息。 display
在每次停止时自动显示指定的变量值。 undisplay
停止自动显示变量值。
粘性模式(Sticky Mode)
sticky
模式是pdb++
中的一个特殊功能,它会在调试时持续显示当前代码的上下文。每次程序执行到下一行,pdb++
会自动刷新并显示当前位置的代码片段。
启用/禁用:
- 输入
sticky
切换模式。使用场景:
- 在调试过程中,
sticky
模式可以帮助你持续观察代码的变化,无需手动调用list
命令。
命令别名
pdb++
允许你为常用命令创建别名,简化调试过程。例如,你可以为longlist
创建一个别名ll
。alias ll longlist
你也可以在
.pdbrc.py
文件中配置这些别名,以便每次启动pdb++
时自动加载。
自定义配置
你可以通过
~/.pdbrc.py
文件自定义pdb++
的行为,例如自动启用语法高亮、粘性模式、设置别名等。示例
.pdbrc.py
文件:# ~/.pdbrc.py# 自动启用粘性模式 def setup(self):self.sticky = True# 设置别名 alias ll longlist alias n next alias s step alias c continue
调试快捷键
快捷键 说明 Ctrl + D
退出调试器。 Ctrl + L
清屏。 Tab
自动补全命令、变量、函数名等。
常用调试工作流
- 启动调试:在代码中插入
import pdb; pdb.set_trace()
,或者运行脚本时通过python -m pdb your_script.py
进入调试模式。- 设置断点:用
break <lineno>
或tbreak
设置断点。- 逐步调试:使用
next
或step
逐行执行代码,检查变量的值。- 检查变量:通过
p
或pp
打印变量的值,使用whatis
查看变量的类型。- 跟踪异常:使用
track
追踪异常的完整回溯信息。- 使用粘性模式:通过
sticky
持续显示代码的上下文,实时跟踪代码执行。
结语
pdb++
是一个强大且灵活的调试工具,它在pdb
的基础上提供了许多增强功能,使调试过程更加高效、直观。通过这份 Cheatsheet,你可以快速掌握pdb++
的常用命令并提升调试效率。
pdb(pdb++)方法
下面是你列出的
pdb++
(和pdb
)中常用函数的详细讲解,包括各个函数的签名、参数说明、用法以及它们的具体作用。在pdb++
中,这些函数提供了灵活的调试能力,可以根据具体需求使用不同的调试方法。
1.
pdb.run(statement, globals=None, locals=None)
作用
- 在调试器中执行一条 Python 语句(类似于
exec()
函数),并在执行该语句时进入调试模式。签名
def run(statement: str, globals: dict[str, Any] | None = None, locals: Mapping[str, Any] | None = None) -> None
参数
statement
: 一个字符串类型的 Python 语句,表示你想要执行的代码。globals
: 可选参数,表示全局命名空间的字典。如果不提供,默认为None
,使用当前的全局命名空间。locals
: 可选参数,表示局部命名空间的映射。如果不提供,默认为None
,使用当前的局部命名空间。用法
import pdbstatement = 'x = 10; y = 20; z = x + y' pdb.run(statement)
说明
pdb.run()
类似于exec()
,但在执行过程中启动调试器,方便你调试一段代码的执行过程。
2.
pdb.runeval(expression, globals=None, locals=None)
作用
- 在调试器中求值一个表达式(类似于
eval()
函数),并返回其结果。这个函数允许你在调试模式下执行表达式并获取结果。签名
def runeval(expression: str, globals: dict[str, Any] | None = None, locals: Mapping[str, Any] | None = None) -> Any
参数
expression
: 一个字符串类型的 Python 表达式,表示你想要计算的表达式。globals
: 可选参数,表示全局命名空间的字典。如果不提供,默认为None
,使用当前的全局命名空间。locals
: 可选参数,表示局部命名空间的映射。如果不提供,默认为None
,使用当前的局部命名空间。用法
import pdbexpression = '10 + 20' result = pdb.runeval(expression) print(result)
说明
pdb.runeval()
类似于eval()
,但在调试器运行环境中执行表达式,并返回计算结果。
3.
pdb.runctx(statement, globals, locals)
作用
- 在调试器中执行一条 Python 语句,并显式传递全局和局部命名空间。这与
pdb.run()
类似,但强制要求提供globals
和locals
参数。签名
def runctx(statement: str, globals: dict[str, Any], locals: Mapping[str, Any]) -> None
参数
statement
: 需要执行的 Python 语句。globals
: 全局命名空间的字典。locals
: 局部命名空间的映射。用法
import pdbglobals = {'a': 10} locals = {'b': 20} statement = 'c = a + b' pdb.runctx(statement, globals, locals) print(globals, locals)
说明
pdb.runctx()
允许你使用自定义的命名空间执行代码,这在调试复杂的上下文时非常有用。
4.
pdb.runcall(func, *args, **kwds)
作用
- 在调试器中调用一个函数,并传递参数。这允许你在调试模式下运行函数并检查其执行过程。
签名
def runcall(func: Callable[_P, _T], *args: _P.args, **kwds: _P.kwargs) -> _T | None
参数
func
: 要调用的函数。*args
: 传递给函数的参数。**kwds
: 传递给函数的关键字参数。用法
import pdbdef divide(a, b):return a / bresult = pdb.runcall(divide, 10, 2) # 调试 divide(10, 2) print(result)
说明
pdb.runcall()
允许你在调试器中运行某些函数,并检查函数执行的每一步。这在调试有参数的函数时非常有用。
5.
pdb.set_trace()
作用
- 手动在代码中设置一个断点,启动调试器并暂停程序执行。
签名
def set_trace(*, header: str | None = None) -> None
参数
header
: 可选参数,类型为str | None
,表示当调试器启动时输出的自定义消息。如果不提供,默认为None
。用法
import pdbdef my_function():x = 10pdb.set_trace(header="调试器启动") # 在这里进入调试模式,显示自定义消息y = 20z = x + yprint(z)my_function()
说明
pdb.set_trace()
是手动调试的常用工具,它允许你在代码执行到某个位置时暂停,并进入调试模式。header
参数可以提供额外的信息,以便在调试器启动时显示。
6.
pdb.post_mortem()
作用
- 在异常发生后启动调试器,允许你查看异常发生时的上下文。这在调试未捕获的错误时非常有用。
签名
def post_mortem(t: TracebackType | None = None) -> None
参数
t
: 可选参数,类型为TracebackType | None
,表示要调试的回溯对象。如果不提供,使用最近的异常回溯。用法
import pdbdef divide(a, b):return a / btry:divide(1, 0) except ZeroDivisionError:pdb.post_mortem() # 在异常发生后进入调试模式
说明
post_mortem()
允许你在异常发生后进入调试器,并检查导致异常的上下文。在调试程序崩溃时非常有用。
7.
pdb.pm()
作用
- 立即进入调试模式,调试最近的未捕获异常。它是
post_mortem()
函数的快捷方式。签名
def pm() -> None
参数
- 无参数。
用法
import pdbdef divide(a, b):return a / btry:divide(1, 0) except:pdb.pm() # 调试最近的未捕获异常
说明
pm()
是post_mortem()
的简化版本,自动处理最近发生的异常并启动调试器。它适合快速进入调试模式,而无需显式捕获异常。
总结
run()
: 在调试模式下执行一条 Python 语句。runeval()
: 在调试模式下求值一个表达式并返回结果。runctx()
: 在调试模式下执行一条 Python 语句,并使用自定义的全局和局部命名空间。runcall()
: 通过调试器调用一个函数,并传递参数。set_trace()
: 手动设置断点,进入调试模式。post_mortem()
: 在异常发生后进入调试模式。pm()
: 调试最近的未捕获异常,是post_mortem()
的快捷方式。这些函数提供了灵活的调试工具集,适合不同的调试需求。
python debug相关环境变量
在 Python 中,调试器(如
pdb
和pdb++
)可以通过一些环境变量进行配置和控制。这些环境变量可以影响调试器的行为、设置以及输出。以下是与 Python 调试相关的主要环境变量:
1.
PYTHONBREAKPOINT
作用:控制程序中断点的行为,特别是用于设置或禁用调试器。
用法:
- 默认值:
PYTHONBREAKPOINT=pdb.set_trace
- 禁用断点:将变量设置为
0
,所有的breakpoint()
调用将被忽略。- 自定义行为:你可以将其设置为任意可调用的调试函数,甚至是自定义函数。
示例:
export PYTHONBREAKPOINT=0 # 禁用所有断点 export PYTHONBREAKPOINT=my_debugger.set_trace # 使用自定义调试器
说明:
- 在 Python 3.7+ 中,
breakpoint()
是用于手动进入调试的内置函数。通过设置PYTHONBREAKPOINT
,你可以更改breakpoint()
的行为。- 如果设置为
0
,则调试功能被禁用,即所有breakpoint()
调用将被忽略。
2.
PYTHONWARNINGS
作用:控制 Python 警告的显示方式,通常用于调试时查看潜在问题。
用法:
- 默认值:Python 默认只显示一次警告。
- 可以设置成
error
来将警告变为异常,这样在调试器中可以捕获并调试警告。格式:
PYTHONWARNINGS=action:message:category:module:line
(其中,action
是最常用的部分)常见值:
default
:默认行为,显示一次警告。always
:总是显示警告。ignore
:忽略警告。error
:将警告转换为异常。module
:每个模块显示一次警告。once
:仅显示一次警告。示例:
export PYTHONWARNINGS="error" # 将所有警告视为错误 export PYTHONWARNINGS="always" # 总是显示所有警告
说明:
- 当你设置
PYTHONWARNINGS="error"
时,所有 Python 警告将作为异常抛出,这样你可以在调试器中捕获它们并查看具体的堆栈信息。- 这在调试潜在的代码问题或需要严格处理警告时非常有用。
3.
PYTHONTRACEMALLOC
作用:启用或禁用内存分配跟踪,用于调试内存泄漏问题。
用法:
- 默认值:未启用。
- 设置为正整数值来控制分配追踪的深度。
示例:
export PYTHONTRACEMALLOC=1 # 启用内存分配跟踪,深度为 1 export PYTHONTRACEMALLOC=5 # 启用内存分配跟踪,深度为 5
说明:
- 启用内存跟踪后,Python 将记录内存分配的堆栈信息。这对于调试内存泄漏或定位高内存使用问题非常有帮助。
- 你可以使用
tracemalloc
模块来获取和显示内存分配的相关信息。
4.
PYTHONDEBUG
作用:启用 Python 解释器的调试输出,由解释器在启动时使用。
用法:
- 设置为任意非空值时,启用调试模式(解释器的调试信息将输出到标准错误流)。
示例:
export PYTHONDEBUG=1 # 启用解释器的调试模式
说明:
- 启用
PYTHONDEBUG
后,Python 会输出更多的调试信息,包括一些内部机制的输出内容。这对于调试 Python 解释器本身或者查看解释器的详细运行信息非常有用。
5.
PYTHONVERBOSE
作用:启用详细输出模式,用于显示 Python 解释器加载模块的详细信息,适合调试模块导入问题。
用法:
- 设置为任意非空值时,启用详细模式。
示例:
export PYTHONVERBOSE=1 # 启用详细输出模式
说明:
- 启用
PYTHONVERBOSE
后,Python 会在程序执行过程中输出每个模块导入的详细信息。这对调试模块导入路径、导入冲突或未找到模块的问题非常有帮助。
6.
PYTHONMALLOC
作用:控制 Python 的内存分配器类型,用于调试内存分配和内存问题。
可选值:
malloc
:使用系统的malloc()
。pymalloc
:使用 Python 的小对象分配器(默认)。debug
:使用 Python 的小对象分配器,并启用内存调试。示例:
export PYTHONMALLOC=debug # 启用内存调试
说明:
- 设置为
debug
时,Python 会启用内存分配调试机制,帮助你发现内存分配错误或内存泄漏问题。
7.
PYTHONFAULTHANDLER
作用:启用 Python 的故障处理程序,使得 Python 在崩溃时打印出详细的堆栈信息。
用法:
- 设置为任意非空值,启用故障处理程序。
示例:
export PYTHONFAULTHANDLER=1 # 启用故障处理程序
说明:
- 启用
PYTHONFAULTHANDLER
后,当 Python 崩溃时,它会打印出 Python 错误堆栈信息,帮助你更容易地定位问题。特别是在调试 C 扩展模块或者解释器崩溃时非常有用。
8.
PYTHONHASHSEED
作用:控制字符串和其他哈希种子的初始化值。
用法:
- 设置为一个整数值,用于确定 Python 的哈希种子。
- 随机哈希种子默认用于防止哈希冲突攻击,但在某些情况下(如调试或测试),你可能希望使用固定值。
示例:
export PYTHONHASHSEED=42 # 使用固定的哈希种子
说明:
- 在调试涉及哈希的代码(如字典、集合)时,使用固定的哈希种子可以帮助你复现和调试某些哈希相关的错误。
9.
PYTHONINSPECT
作用:在程序运行结束后自动进入交互模式(REPL),可用于调试。
用法:
- 设置为任意非空值时,程序运行结束后进入交互模式。
示例:
export PYTHONINSPECT=1 # 程序结束后进入交互模式
说明:
- 启用
PYTHONINSPECT
后,当 Python 程序执行结束时,它会启动交互式解释器(REPL)。这在你想要在程序结束后进一步检查状态时非常有用。
总结
以下是常见的与 Python 调试相关的环境变量:
PYTHONBREAKPOINT
:控制breakpoint()
的行为。PYTHONWARNINGS
:控制警告的处理方式。PYTHONTRACEMALLOC
:启用内存分配跟踪。PYTHONDEBUG
:启用解释器调试模式。PYTHONVERBOSE
:启用详细输出模式,调试模块导入问题。PYTHONMALLOC
:控制 Python 的内存分配器。PYTHONFAULTHANDLER
:启用故障处理程序,捕获崩溃时的堆栈信息。PYTHONHASHSEED
:设置固定的哈希种子,调试哈希相关问题。PYTHONINSPECT
:程序执行结束后进入交互模式。这些环境变量为开发者提供了灵活的调试选项,适用于不同的调试场景和调试需求。
注意
breakpoint()
和set_trace()
有一些细小差别。