在生产环境,我们一般会把项目布置在服务器上,和我们的本地调试环境不同,服务器一般都是无GUI界面的,一旦在生产环境出了问题,只能在字符界面下调试.于是乎,我们pycharm的断点大法彻底歇菜.那么,在字符界面,一般都用什么调试方式呢? 在这里,我推荐给大家的是jupyter+pdb/ipdb的组合来在字符界面进行调试.
首先说编辑器.很多人在windows环境下习惯了图形界面的人,可能不太适应vi之流的的字符界面的编辑器,觉得需要记忆的快捷键太多.而且python语法特有的缩进问题,很容易导致编辑后的py文件无法运行.那么,有什么好的替代方案吗? 有!,就是jupyter,也就是以前我们说的IPython notebook.以下逐步举例说明,注意,我用的是python3,对应的pip命令是pip3,如果你是python2,请自行改为pip命令.
先安装jupyter
pip3 install jupyter
然后切换到你的站点/项目目录,比如的项目目录在 /home/web/下面.我就:
cd /home/web/
运行jupyter
在项目根目录下面运行
jupyter notebook --ip=0.0.0.0 --port 8998 --allow-root
说明一下:
--ip 是你绑定的ip地址.
--port 是你绑定的端口.
--allow-root 如果你不是使用root账户的话,可以不加这一参数.
程序运行起来后,会有一行这样的提示:
Copy/paste this URL into your browser when you connect for the first time,
to login with a token:
http://0.0.0.0:8998/?token=8e70bede7af9ad0a9dd9120cb5eb1cfa8db32995021e18fd
意思让你用"http://0.0.0.0:8998/?token=8e70bede7af9ad0a9dd9120cb5eb1cfa8db32995021e18fd"这个地址登录,实际上,你要把0.0.0.0替换成真实的ip地址.比如"http://192.168.0.49:8998/?token=8e70bede7af9ad0a9dd9120cb5eb1cfa8db32995021e18fd"
然后就看见了项目目录:
这个时候,你就可以随意编辑服务器上的项目文件了.
安装 ipdb
其实这一步不是必须的,python 自带的pdb就足够了,但ipdb是个人偏好,我喜欢彩色的字.哈哈
pip3 install ipdb
软断点和硬断点
我们知道,一般我们使用ipdb调试的时候,使用的是软断点模式.
python3 -m ipdb your.py
-m参数是以脚本的形式运行python3下安装的库. 这个参数经常使用.
这样我们就可以以交互的方式使用 break line_number的方式打一个软断点,然后按c继续运行.我下面先举个例子.
我的代码是这样的. extends_func.py
# -*-coding:utf-8-*-
from uuid import uuid4
def add_uuid(part_str: str) -> str:
"""
把一段字符串后面加上一段uuid,这么无聊的程序当然是用来演示啦.
:param part_str: 字符串
:return:part_str + uuid
"""
if part_str is None:
ms = "part_str参数不能为空"
raise TypeError(ms)
else:
if not isinstance(part_str, str):
part_str = str(part_str)
else:
pass
return part_str + uuid4().hex
if __name__ == "__main__":
add_uuid("a")
pass
然后我们使用ipdb运行这个脚本
python3 -m ipdb extends_func.py
ipdb启动后,会停在脚本的开头,等待你输入命令.
这时候你可以使用break line_number打一个软断点,这个命令有个快捷方式,就是b.比如
b 11 就是在当前脚本的第11行打一个断点.b后面也可以跟一个函数名,这样断点就打在函数的入口处.当然断点你也可以打在其他脚本上,前提是你不要输错路径.
这里我们把断点打在当前脚本的第14行,在ipdb的提示符下输入 b 11 然后回车.
walle@walle-Vostro-3559:~/work/projects/flask_01$ python3 -m ipdb extends_func.py
> /home/walle/work/projects/flask_01/extends_func.py(2)<module>()
1 # -*-coding:utf-8-*-
----> 2 from uuid import uuid4
3
ipdb> b 11
Breakpoint 1 at /home/walle/work/projects/flask_01/extends_func.py:11
ipdb>
然后输入c回车,让程序继续运行.程序会在我们的断点位置停下,然后我们就可以做很多事情........
walle@walle-Vostro-3559:~/work/projects/flask_01$ python3 -m ipdb extends_func.py
> /home/walle/work/projects/flask_01/extends_func.py(2)<module>()
1 # -*-coding:utf-8-*-
----> 2 from uuid import uuid4
3
ipdb> b 11
Breakpoint 1 at /home/walle/work/projects/flask_01/extends_func.py:11
ipdb> c
> /home/walle/work/projects/flask_01/extends_func.py(11)add_uuid()
10 """
1--> 11 if part_str is None:
12 ms = "part_str参数不能为空"
ipdb>
这在一般的脚本调试中是很好用的,而且不像硬断点,对原始代码没有污染.不过,我们有很多web项目(比如flask项目),服务器脚本都是处于阻塞状态的, 这种软断点无法生效.只能使用硬断点的方式了.
设置硬断点
直接上代码
# -*-coding:utf-8-*-
from flask import Flask
from flask import request
from extends_func import add_uuid
from pdb import set_trace # 引入跟踪函数
port = 7777
app = Flask(__name__)
@app.route("/")
def hello():
set_trace() # 设置硬断点
name = request.args.get("name")
res = add_uuid(name)
return res
if __name__ == "__main__":
app.run(host='0.0.0.0', port=port, debug=True)
然后我们另开一个窗口,把站点项目跑起来.
root@ubuntu-server:/home/web/flask_01# python3 f_server.py
然后我们访问站点的首页.程序会在硬断点的位置停下来.
^Croot@ubuntu-server:/home/web/flask_01# python3 f_server.py
* Restarting with stat
* Debugger is active!
* Debugger PIN: 303-929-595
> /home/web/flask_01/f_server.py(15)hello()
14 set_trace() # 设置硬断点
---> 15 name = request.args.get("name")
16 res = add_uuid(name)
ipdb>
然后你可以idb后面输入命令,进行调试了.常用的几个命令如下:
命令 说明
n 单步,不会进子程序
s 单步,会进子程序
c 跳到下个断点
p arg_name 查看变量值,arg_name是变量名
l 查看附近区域代码
b line_number 打软断点
condition break_number [expression] 条件断点,break_number断点编号,可以输入l查看,expression 是条件 比如 a is None
h 帮助文件
var = value 赋值, 比如 name = 'jack'
cl [break_number] 清除断点 ,没有break_number是清除全部断点.
a 打印当前函数的参数
q 退出