python代码调试中间变量_python pdb调试代码

在工作中,你可以使用pdb查看你的代码错误。当你学习某个程序时,你可以可以使用pdb调试它的逻辑。当然你也可以选择其他的调试器,但是使用debugger是作为程序员必备的一项技能。pdb也是python的标准库的一部分。

开始吧!首先来打印一个变量的值

首先将下面的代码放在你想要打断点的地方

import pdb; pdb.set_trace()

当代码执行到这句话的时候,程序会停下来,等待你的指令。在(Pdb)上键入命令即可。另外,值得关注的是,从python3.7开始,有更方便的内置调试函数,breakpoint()。用这个会更加灵活,你可以通过调用它的API和环境变量PYTHONBREAKPOINT控制调试过程。如果你是3.7以上的版本推荐你使用这个。

当然你也可以不必要非得加上上面的调试语句才能进行调试,你可以加上-m pdb参数进行调试,如果你的应用需要参数,也可以正常加上参数。

python3 -m pdb app.py arg1 arg2

pdb有很多的调试命令,让我先用p来打印变量吧

运行下面这段代码,example1.py

#!/usr/bin/env python3

filename = __file__

import pdb; pdb.set_trace()

print(f'path = {filename}')

出现下面的结果

$ ./example1.py

> /code/example1.py(5)()

-> print(f'path = {filename}')

(Pdb)

键入p filename得到下面的结果

(Pdb) p filename

'./example1.py'

(Pdb)

可以使用ctrl+c或者q退出调试

打印表达式

请看下面的代码

#!/usr/bin/env python3

import os

def get_path(filename):

"""Return file's path or empty string if no path."""

head, tail = os.path.split(filename)

import pdb; pdb.set_trace()

return head

filename = __file__

print(f'path = {get_path(filename)}')

运行上面的代码,在命令提示行中依次输入下面的命令

(Pdb) ll

6 def get_path(filename):

7 """Return file's path or empty string if no path."""

8 head, tail = os.path.split(filename)

9 import pdb; pdb.set_trace()

10 -> return head

(Pdb) p filename

'./example2.py'

(Pdb) p head, tail

('.', 'example2.py')

(Pdb) p 'filename: ' + filename

'filename: ./example2.py'

(Pdb) p get_path

(Pdb) p getattr(get_path, '__doc__')

"Return file's path or empty string if no path."

(Pdb) p [os.path.split(p)[1] for p in os.path.sys.path]

['pdb-basics', 'python36.zip', 'python3.6', 'lib-dynload', 'site-packages']

(Pdb)

你会发现你可以打印出所有有效的python表达式

单步调试n: 继续执行下一步

s:进到当前的执行到的函数内部去执行

执行下面的代码,examples3.py

#!/usr/bin/env python3

import os

def get_path(filename):

"""Return file's path or empty string if no path."""

head, tail = os.path.split(filename)

return head

filename = __file__

import pdb; pdb.set_trace()

filename_path = get_path(filename)

print(f'path = {filename_path}')

看看n 和s 的效果,下面是n

$ ./example3.py

> /code/example3.py(14)()

-> filename_path = get_path(filename)

(Pdb) n

> /code/example3.py(15)()

-> print(f'path = {filename_path}')

(Pdb)

然后是s

$ ./example3.py

> /code/example3.py(14)()

-> filename_path = get_path(filename)

(Pdb) s

--Call--

> /code/example3.py(6)get_path()

-> def get_path(filename):

(Pdb)

当使用s进到函数内部执行完之后,然后按原路返回原先的代码处

展示源码

使用ll可以查看你当前代码执行的上下文源码,运行下面的代码

$ ./example3.py

> /code/example3.py(14)()

-> filename_path = get_path(filename)

(Pdb) s

--Call--

> /code/example3.py(6)get_path()

-> def get_path(filename):

(Pdb) ll

6 -> def get_path(filename):

7 """Return file's path or empty string if no path."""

8 head, tail = os.path.split(filename)

9 return head

(Pdb)

如果你要查看稍微短点的代码,可以直接使用l,但是一直用这个l会打印到下面的代码去,加上参数.就会一直展示当前代码的上下11行代码了。请看下面的使用

$ ./example3.py

> /code/example3.py(14)()

-> filename_path = get_path(filename)

(Pdb) l

9 return head

10

11

12 filename = __file__

13 import pdb; pdb.set_trace()

14 -> filename_path = get_path(filename)

15 print(f'path = {filename_path}')

[EOF]

(Pdb) l

[EOF]

(Pdb) l .

9 return head

10

11

12 filename = __file__

13 import pdb; pdb.set_trace()

14 -> filename_path = get_path(filename)

15 print(f'path = {filename_path}')

[EOF]

(Pdb)

断点

有时候你可能不想一步一步查看所有的代码,这时候断点就起作用了。断点的语法如下:

b(reak) [ ([filename:]lineno | function) [, condition] ]

你可以根据行号打断点,也可以根据代码逻辑大断点,请看下面的example4.py

#!/usr/bin/env python3

import util

filename = __file__

import pdb; pdb.set_trace()

filename_path = util.get_path(filename)

print(f'path = {filename_path}')

还有一个文件util.py

def get_path(filename):

"""Return file's path or empty string if no path."""

import os

head, tail = os.path.split(filename)

return head

打个断点看看

$ ./example4.py

> /code/example4.py(7)()

-> filename_path = util.get_path(filename)

(Pdb) b util:5

Breakpoint 1 at /code/util.py:5

(Pdb) c

> /code/util.py(5)get_path()

-> return head

(Pdb) p filename, head, tail

('./example4.py', '.', 'example4.py')

(Pdb)

当前在examples4里面执行,断点打在util.py文件的第5行,按c之后代码直接跳到util.py的第5行继续执行。或者使用函数名打断点也是可以的

$ ./example4.py

> /code/example4.py(7)()

-> filename_path = util.get_path(filename)

(Pdb) b util.get_path

Breakpoint 1 at /code/util.py:1

(Pdb) c

> /code/util.py(3)get_path()

-> import os

(Pdb) p filename

'./example4.py'

(Pdb)

只键入一个b,不带参数,会列出断点列表

(Pdb) b

Num Type Disp Enb Where

1 breakpoint keep yes at /code/util.py:1

(Pdb)

可以根据前面的数值激活或者取消断点,请看下面的代码

(Pdb) disable 1

Disabled breakpoint 1 at /code/util.py:1

(Pdb) b

Num Type Disp Enb Where

1 breakpoint keep no at /code/util.py:1

(Pdb) enable 1

Enabled breakpoint 1 at /code/util.py:1

(Pdb) b

Num Type Disp Enb Where

1 breakpoint keep yes at /code/util.py:1

(Pdb)

你也可以使用cl(ear)删除断点

cl(ear) filename:lineno

cl(ear) [bpnumber [bpnumber...]]

还有一种根据表达式设置断点的例子,没用过,不常用,这里不多做介绍了

查看调用棧

可以使用w查看调用棧,请看下面的例子example5.py

#!/usr/bin/env python3

import fileutil

def get_file_info(full_fname):

file_path = fileutil.get_path(full_fname)

return file_path

filename = __file__

filename_path = get_file_info(filename)

print(f'path = {filename_path}')

另一个文件fileutil.py

def get_path(fname):

"""Return file's path or empty string if no path."""

import os

import pdb; pdb.set_trace()

head, tail = os.path.split(fname)

return head

运行例子

$ ./example5.py

> /code/fileutil.py(5)get_path()

-> head, tail = os.path.split(fname)

(Pdb) w

/code/example5.py(12)()

-> filename_path = get_file_info(filename)

/code/example5.py(7)get_file_info()

-> file_path = fileutil.get_path(full_fname)

> /code/fileutil.py(5)get_path()

-> head, tail = os.path.split(fname)

(Pdb)

可以看到打印出了当前的调用棧,也就是进到这个函数的上一层调用,另外还有两个命令,一个u可以继续往调用棧上走,w是往调用棧下走

好了,平时常用的调试命令就介绍到这里了,你要是有什么不懂的,可以使用h 查看所有的命令列表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值