引言
调试是程序员的一项基本技能,是一门手艺,我们需要不断练习才能做得更好。在这里,我总结了调试 Python 代码的有用技巧和工具。
1. 查看函数或对象的源代码
了解实现的细节对于调试至关重要。在调试 Python 代码时,你可能想知道模块、类、方法、函数、回溯、框架或代码对象的源代码。检查模块将帮助你:
import inspect
def add(x, y):
return x + y
class Dog:
kind = 'dog' # class variable shared by all instances
def __init__(self, name):
self.name = name # instance variable unique to each instance
def eat(food):
print("eating ..." + food)
print(inspect.getsource(add))
print(inspect.getsource(Dog))
print(inspect.getsource(Dog.eat))
2. 把日志打印到文件中
日志是我们理解代码运行时最重要的线索。打印出日志是跟踪程序执行流程的有用方法。
但是,用 Python 打印只能输出到终端,对于复杂的故障排除,尤其是对于服务器端应用程序来说,这远远不是理想的方法。
Python 3中的 print 函数更加强大,因为它可以接受更多的参数,并且指定一些参数可以将 print 的内容输出到日志文件中。
with open('test.log', mode='w') as f:
print('hello, python', file=f, flush=True)
另一个有用和灵活的模块是日志,我们可以设置输出文件名,日志格式等。
import logging
logging.basicConfig(filename='app.log', filemode='w',
format='%(name)s - %(levelname)s - %(message)s')
a = 5
b = 0
try:
c = a / b
except Exception as e:
logging.exception("Exception occurred")
3. 追踪执行时间
对于性能问题,我们需要计算一个函数的运行时间:
import time
start = time.time()
# run the function
end = time.time()
print(end-start)
有一个内置的模块叫做 timeit,我们可以使用它只用一行代码来跟踪时间:
import time
import timeit
def run_sleep(second):
print(second)
time.sleep(second)
print(timeit.timeit(lambda :run_sleep(2), number=1))
4. 交互式调试
REPL 支持增量交互式开发风格,交互式调试是一种更有效的方式。理想的工作流是重复的编辑运行过程。
要调用具有交互式会话的程序,我们需要添加-i 选项:
python -i demo.py
为了简化您的工作,importlib.reload (module)是避免重新启动交互式会话的合适方法。
让我们举个例子,假设我们运行了一个名为 demo 的函数,为了解决一个问题,我们需要对这个函数做一些修改,然后 reload (module)将加载修改后的 demo 版本,而不需要重新启动会话:
>>> from importlib import reload
>>> import demo from module
>>> demo()
"The result of demo..."
# Make some changes to "demo"
>>> demo()
"The result of demo..." # The Outdated result
>>> reload(module) # Reload "module" after changes made to "demo"
>>> demo()
"This will be the new result..."
>>> # repeat the circle of fix-and-retry
这将节省大量的调试时间。
5. 使用 pdb
Python 有一个名为 pdb 的模块来支持交互式源代码调试器。它支持在行级设置断点,即单步执行。此外,pdb 打印检查堆栈帧,变量值,检查源代码等。
要使用调试器启动程序,请添加-m pdb选项以调用脚本:
user@coderscat:~/snippets$ python3.7 -m pdb demo.py
> /home/user/snippets/demo.py(1)<module>()
-> import inspect
(Pdb) l
1 -> import inspect
2
3 def gcd(a,b):
4 if(b==0):
5 return a
6 else:
7 return gcd(b,a%b)
8
9
10 print(gcd(34, 34))
[EOF]
(Pdb) b demo.py:3
Breakpoint 1 at /home/user/snippets/demo.py:3
(Pdb) c
> /home/user/snippets/demo.py(3)<module>()
-> def gcd(a,b):
(Pdb) step
> /home/user/snippets/demo.py(10)<module>()
-> print(gcd(34, 34))
(Pdb)
从正在运行的程序中断调试器的另一个典型用法是插入:
import pdb; pdb.set_trace()
下面是一些有用的 pdb 命令
· list(l):显示 Python 解释器当前所在的代码行
· step(s):逐行继续执行,逐步执行函数
· next(n) : 继续下一行代码
· break(b) : 在当前行上设置新断点
· continue(c) : 继续执行,直到下一个断点
在大多数情况下,我们不需要执行所有步骤,pdb 是调试 Python 程序的终极工具。
总结
在调试 Python 代码时,可以尝试这些技巧和工具。为了提高你的调试技巧,熟能生巧!
· END ·
HAPPY LIFE