最终我们要将程序从开发环境部署到生产环境。令程序支持几套不同的配置方案颇有难度。某些内置的Python模块可以帮我们优化程序的调试、优化、测试,努力提升程序品质。

54. 考虑用模块级别的代码来配置不同的部署环境

  • 使用配置项明确指出现在运行的是开发环境还是生产环境。

  • 可以通过sysos模块查询当前宿主机器的特性,以此决定模块的内容、逻辑。

55. 通过repr字符串来输出调试信息

  • 使用普通的print输出的调试信息有两个问题:

    1. 不能清晰地表明变量的类型。例如print(5)print('5')的输出是一样的。

    2. 对象被打印前会被自动调用repr函数,但打印出是类似<__main__.SomeClass object at 0x107880ba8>的内容,不是很有用。

  • 第1个问题,需要使用print(repr(5))或者print('%r',5)才能打印出来。

  • 第2个问题,需要为我们自己的类定义__repr__方法。如果是我们无法改写的类,可以通过print(obj.__dict__)来观察其内部信息。

56. 用unitest来测试全部代码

  • Python的动态特性,一方面阻碍了静态类型检查,另一方面使得我们可以更方便的编写测试代码,我们动态覆盖相关行为来实现更灵活的测试。

  • Python内置的unitest模块可以方便的开发测试用例。请自行学习unitest模块的使用方法(主要是TestCase类)。

  • Python3还有unitest.mock模块可以动态替换受测程序中的行为。

57. 考虑用pdb实现交互式调试

  • 可以在代码中加入import pdb; pdb.set_trace()这么一行代码,运行到此处时将会启动交互式调试界面:
-> import pdb; pdb.set_trace() # 这样一行代码可以很方便的被注释掉
(Pdb)
  • 请自行学习pdb的更多使用方法。

58. 先分析性能,然后再优化

  • Python程序的运行效率可能与我们预想的结果有很大差距,我们可以使用内置的性能分析工具(profiler)。

  • 有两种内置的profiler,一种是Python实现的(名字叫profile),一种是C实现的扩展模块(名字叫cProfile)。推荐后者,因为它对受测程序产生的影响小很多,更加准确。

  • 请自行学习cProfile模块的使用方法(主要是runcall方法分析性能,通过Stats对象获取分析数据)。

59. 通过tracemalloc来掌握内存的使用及泄露情况

  • Python的默认实现CPython通过引用计数和循环引用检测(cycle detector)来进行垃圾回收。通常我们不用担心垃圾回收问题,但是有时我们还是因为保留了过多的引用导致内存耗尽。

  • 我们可以使用内置的gc模块查询内存分配情况,主要是使用gc.get_objects()方法获得所有分配的对象,选取其中最小的样本展示出来,比如打印gc.get_objects()[:3]

  • Python3.4新推出的内置模块tracemalloc可以知道对象分配的地点。请自行学习该模块的使用方法。