目录 | 上一节 (8.2 日志) | 下一节 (9 包)

8.3 调试

调试建议

假设程序崩溃了:

bash % python3 blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
AttributeError: 'int' object has no attribute 'append'

那么现在该怎么办呢?

阅读回溯信息

最后一行是程序崩溃的具体原因:

bash % python3 blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
# Cause of the crash
AttributeError: 'int' object has no attribute 'append'

不过,回溯信息并不总是那么易于阅读或理解。

专业建议:将整个回溯粘贴到谷歌。

使用交互式解释器(REPL)

执行脚本的 时候,可以使用选项 -i 使 Python 保持存活(keep alive)。

bash % python3 -i blah.py
Traceback (most recent call last):
File "blah.py", line 13, in ?
foo()
File "blah.py", line 10, in foo
bar()
File "blah.py", line 7, in bar
spam()
File "blah.py", 4, in spam
line x.append(3)
AttributeError: 'int' object has no attribute 'append'
>>>

选项 -i 可以保留解释器状态。这意味着可以在程序崩溃后查找错误信息。对变量的值和其它状态进行检查。

使用打印进行调试

使用 print() 函数进行调试非常常见。

建议:确保使用的是 repr() 函数。

def spam(x):
print('DEBUG:', repr(x))
...

repr() 函数显示一个值的准确表示,而不是格式良好的输出。

>>> from decimal import Decimal
>>> x = Decimal('3.4')
# NO `repr`
>>> print(x)
3.4
# WITH `repr`
>>> print(repr(x))
Decimal('3.4')
>>>

Python 的调试器

可以在程序内手动启动调试器(debugger)。

def some_function():
...
breakpoint() # Enter the debugger (Python 3.7+)
...

上述操作会在 breakpoint() 调用时启动调试器。

在 Python 的早期版本中,可能会看到下面这样的调试指南:

import pdb
...
pdb.set_trace() # Instead of `breakpoint()`
...

(译注:Python 3.7 之后,可以使用内置函数 breakpoint() 代替 import pdb; pdb.set_trace())

在调试解释器下运行程序

也可以在调试器下运行整个程序:

bash % python3 -m pdb someprogram.py

上述操作会在第一行语句之前自动进入调试器,允许设置断点和修改配置。

常见的调试器命令:

(Pdb) help            # Get help
(Pdb) w(here) # Print stack trace
(Pdb) d(own) # Move down one stack level
(Pdb) u(p) # Move up one stack level
(Pdb) b(reak) loc # Set a breakpoint
(Pdb) s(tep) # Execute one instruction
(Pdb) c(ontinue) # Continue execution
(Pdb) l(ist) # List source code
(Pdb) a(rgs) # Print args of current function
(Pdb) !statement # Execute statement

断点的位置可以用下列任意一种方式进行表示:

(Pdb) b 45            # Line 45 in current file
(Pdb) b file.py:45 # Line 34 in file.py
(Pdb) b foo # Function foo() in current file
(Pdb) b module.foo # Function foo() in a module

练习

练习 8.4:Bugs? 什么是 Bugs?

有 bug,我们就解决 bug(It runs. Ship it!)。

目录 | 上一节 (8.2 日志) | 下一节 (9 包)

注:完整翻译见 https://github.com/codists/practical-python-zh

翻译:《实用的Python编程》08_03_Debugging的更多相关文章

  1. 翻译:《实用的Python编程》InstructorNotes

    实用的 Python 编程--讲师说明 作者:戴维·比兹利(David Beazley) 概述 对于如何使用我的课程"实用的 Python 编程"进行教学的问题,本文档提供一些通用 ...

  2. 翻译:《实用的Python编程》README

    欢迎光临 大约 25 年前,当我第一次学习 Python 时,发现 Python 竟然可以被高效地应用到各种混乱的工作项目上,我立即被震惊了.15 年前,我自己也将这种乐趣教授给别人.教学的结果就是本 ...

  3. 翻译:《实用的Python编程》05_02_Classes_encapsulation

    目录 | 上一节 (5.1 再谈字典) | 下一节 (6 生成器) 5.2 类和封装 创建类时,通常会尝试将类的内部细节进行封装.本节介绍 Python 编程中有关封装的习惯用法(包括私有变量和私有属 ...

  4. 翻译:《实用的Python编程》04_02_Inheritance

    目录 | 上一节 (4.1 类) | 下一节 (4.3 特殊方法) 4.2 继承 继承(inheritance)是编写可扩展程序程序的常用手段.本节对继承的思想(idea)进行探讨. 简介 继承用于特 ...

  5. 翻译:《实用的Python编程》01_02_Hello_world

    目录 | 上一节 (1.1 Python) | 下一节 (1.3 数字) 1.2 第一个程序 本节讨论有关如何创建一个程序.运行解释器和调试的基础知识. 运行 Python Python 程序始终在解 ...

  6. 翻译:《实用的Python编程》03_03_Error_checking

    目录 | 上一节 (3.2 深入函数) | 下一节 (3.4 模块) 3.3 错误检查 虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节. 程序是如何运行失败的 Python 不 ...

  7. 翻译:《实用的Python编程》03_04_Modules

    目录 | 上一节 (3.3 错误检查) | 下一节 (3.5 主模块) 3.4 模块 本节介绍模块的概念以及如何使用跨多个文件的函数. 模块和导入 任何一个 Python 源文件都是一个模块. # f ...

  8. 翻译:《实用的Python编程》03_05_Main_module

    目录 | 上一节 (3.4 模块) | 下一节 (3.6 设计讨论) 3.5 主模块 本节介绍主程序(主模块)的概念 主函数 在许多编程语言中,存在一个主函数或者主方法的概念. // c / c++ ...

  9. 翻译:《实用的Python编程》04_01_Class

    目录 | 上一节 (3.6 设计讨论) | 下一节 (4.2 继承) 4.1 类 本节介绍 class 语句以及创建新对象的方式. 面向对象编程(OOP) 面向对象编程是一种将代码组织成对象集合的编程 ...

随机推荐

  1. 使用控制台启动Android设备模拟器

    文档 > emulator -list-avds Nexus_5X_API_28_x86 Pixel_2_XL_API_28 > emulator.exe -avd Pixel_2_XL_ ...

  2. JavaScript中判断对象是否属于Array类型的4种方法及其背后的原理与局限性

    前言 毫无疑问,Array.isArray是现如今JavaScript中判断对象是否属于Array类型的首选,但是我认为了解本文其余的方法及其背后的原理与局限性也是很有必要的,因为在JavaScrip ...

  3. django学习-10.django连接mysql数据库和创建数据表

    1.django模型 Django对各种数据库提供了很好的支持,包括:PostgreSQL.MySQL.SQLite.Oracle. Django为这些数据库提供了统一的调用API. 我们可以根据自己 ...

  4. 使用stress进行压力测试

    本文转载自使用stress进行压力测试 导语 stress,顾名思义是一款压力测试工具.你可以用它来对系统CPU,内存,以及磁盘IO生成负载. 安装stress 几乎所有主流的linux发行版的软件仓 ...

  5. 与程序员相关的CPU缓存知识

    本文转载自与程序员相关的CPU缓存知识 基础知识 首先,我们都知道现在的CPU多核技术,都会有几级缓存,老的CPU会有两级内存(L1和L2),新的CPU会有三级内存(L1,L2,L3 ),如下图所示: ...

  6. clipse中mybatis的xml配置文件代码提示

    编写mybatis的xml文件时,没有代码提示会很麻烦,是有解决办法的: 按下图打开 点击右上角的Add按钮,添加配置,配置如下,添加后点击OK: Location:http://mybatis.or ...

  7. Coposition 详解

    LifeCycle Hooks 在新版的生命周期函数,可以按需导入到组件中,且只能在setup()函数中使用. import { onMounted, onUnmounted } from 'vue' ...

  8. pyinstaller打包exe运行失败

    使用Pyinstaller来打包自己开发的软件时遇到的几个问题及解决方法.工具主要功能是数据分析,使用机器学习算法完成数据训练和预测功能.主要用到了两个学习库keras和sklearn,所以说在打包时 ...

  9. 《C++ Primer》笔记 第13章 拷贝控制

    拷贝和移动构造函数定义了当用同类型的另一个对象初始化本对象时做什么.拷贝和移动赋值运算符定义了将一个对象赋予同类型的另一个对象时做什么.析构函数定义了当此类型对象销毁时做什么.我们称这些操作为拷贝控制 ...

  10. 鸿蒙的js开发部模式18:鸿蒙的文件上传到python服务器端

    1.首先鸿蒙的js文件上传,设置目录路径为: 构建路径在工程主目录下: 该目录的说明见下面描述: 视图构建如下: 界面代码: <div class="container"&g ...