《Python高级编程》(第二版) ——速查笔记 第10~14章 完结

第十章 测试驱动开发 TDD test-driven Development

1. 简单的测试介绍

  1. 为何使用TDD
  • 可以在实际软件未开始,或者函数未实现的情况下,编写测试用例并不断壮大测试用例,以完成测试用例为目标来开发软件。
  • 可以防止软件回归(新版本发生了旧版本发生的问题)因为是测试驱动开发,所以测试不可少,利于发现问题位置。
  • 提高代码质量 将开发者关注点放在业务逻辑上,提高代码质量。
  • 利用测试可以提高软件内部原理最好的解释
  • 更快的编写更健壮的代码 使用TDD能让代码调试的时间减短,减少代码构建时间(局部测试、降低构建时间)
  1. 日常存在那些测试
  • 验收测试 由客户或者客户目标构件的最终测试,通过这种测试后认为其具备交付条件。
  • 单元测试 可以测试模块 函数 代码块等 最细颗粒度的测试
  • 功能测试 针对某种功能的测试 在给定替代环境下检测单一功能的测试
  • 集成测试,与功能测试相近比其测试的模块级别更高,也是在给定非生产环境下的测试。
  • 负载和性能测试 web负载测试,只提供指标值不提供最终结果(需要人为判定)
  • 代码质量测试 风格违例、文档数量 复杂性指标 静态代码分析警告等
  1. 常用测试工具
  2. unittest (单元\模块测试工具)
- unittest 标准库内组件
- 复写unittest.TestCase 类来创建测试案例 用 unittest.main()方法来调启测试。

类内各个测试 需要用 test_开头,
- 可以写一个 test_suite方法来包裹多个测试的类,进行多个类的测试
2. doctest
-简单理解 特殊的rst文档中记录需要的函数和期望输出,以此来确定测试结果。

2.测试的提高部分

  1. unittest的问题
- 范板代码多,臃肿
- 扩展难
- 难以管理和组织复杂测试 分setup阶段和teardown阶段是绑定到testcase上 难以修改
- 较难收集测试结果组织测试
  1. 替代品 NOSE
- 使用 pip install nose 安装
- 使用 python -m nosetest -v在当前目录下搜索所有可以测试的类和函数(与unittest定义差不多)
- 编写测试固件(脚本) 可以编写 包 模块 测试 三个级别 三个附加函数setup固件加载前 teardown固件加载后 以及 自定义固件加载流程 用with_setup方法来加载相关方法
- 在setuptool 中 提供 test_suite="nose.collector" 值来集成nose
- 用的多还可以在测试文件夹中使用 .noserc 或者 nose.cfg 搞一些全局性配置
- 仍需遵守unittest的函数命名约定
  1. 替代品 py.test
- pip install pytest
- 同样自动搜索相应的测试类和函数。(注意大小写 写错了会停止测试)
- 编写测试固件 跟nose类似
  会自动寻找相应的 setup_module/teardown 方法
- 可以用pytest.fixture()方法装饰测试函数可以使用上面的固件
- 可用 pytest.mark.skipif()方法跳过测试
- 还可以用 ssh驱动分布式测试。  

4.代码覆盖率
- simply coverage来测试代码覆盖率
- 使用命令 coverage run -m unittest 来运行测试覆盖率
- 请注意覆盖率仅仅是测试的通过覆盖率,并不是所有的if else 分支都测试了
5. 仿真与模拟
- 仿真 就是写个跟无法获得类相同返回的类,模拟相关不可达返回创建测试可能性。
- 使用模拟
- pip install Mock
- 调用MagicMock方法来模拟API返回值 P288
6. 测试环境依赖兼容
- tox 建立测试矩阵 P290
7. 文档驱动开发
- 上文中提到的doctest 既测试的功能,又可以很好的解释整个软件的关键点。

3.小结

  • unittest
  • nose py.test
  • 构建仿真和模拟
  • 文档(测试)驱动开发

第十一章 优化 一般分析原则与分析技术

1. 3个优化原则

  1. 首先要能工作——别TM改了以后用不了
  2. 从用户角度考虑——用户关注的点不是你自己关注的点
  3. 保持代码的可读性和可维护性

2. 优化策略

别瞎猜,有对应的流程:

  1. 先找别的东西的原因 ——数据库 访问 I/O 等非代码问题
  2. 扩展硬件 硬件比人工便宜多了…
  3. 编写速度测试 就是time.time() -starttime

3. 查找瓶颈

  1. CPU瓶颈
  • 分为 宏观分析 微观分析
  • 宏观分析 使用cprofile 使用命令 Python3 -m cProfile myapp.py来进行分析 还可以函数内调用 或者配合 graphviz来做更精细的使用 p302
  • 微观分析 当找到耗时较多的函数后 timeit查看多次运行的平均时间 使用test.pystones计算精确时间 p306
  1. 分析内存使用
  • 解释并不给内存管理器的操作权
  • 主要是要靠计数器
  • ogjgraph p311-315
  1. 分析网络使用情况
  • ntop wireshark等
  1. 小结
    优化的3原则、优化策略、具体的一些分析方法及工具。

第十二章 优化 一些强大的技术

代码优化是一个迭代的过程,总的来说就是3个方法

1. 降低复杂度

  • 循环复杂度 McCabe 复杂度(if while …等) 降低代码复杂度
  • 大O记法 降低函数的大O的复杂度

2. 简化

选择优秀的数据存储方式

  • bisect 有序列表查找为 O(logn) 注意有序性强弱

3. 使用集合模块

  • deque 链表 list的链表代替
  • defaultdict 在附值和查找稍微优化相比 dict
  • namedtuple 使用tupe 可以用属性方法调用tupe元素 P326

4. 架构体系的权衡

  • 是使用最佳算法 还是使用近似算法 TSP问题
  • 使用队列处理延迟问题
  • 使用概率型数据结构(大概率情况优化)

5. 缓存

  • 确定的缓存 注意缓存占用
  • 非确定性缓存 同步性与性能取舍
  • memcached 缓存服务

6. 小结

  • 降低算法复杂度的方法
  • 架构层权衡 提高性能
  • 缓存

第十三章 并发

1. 为何需要并发

并发不是并行,处理并发可以是并行(多进程)也可以是轮询(多线程)也可以是事务型(异步)
可以让界面马上可操作,可以让I/O阻塞型任务更高效,让部分多用户 分发模式的任务逻辑更简单

2. 多线程

同一个上下文环境中 不同的任务 就是一个线程

  1. Python中的多线程 有GIL 不能用多核加速 对I/O阻塞型事物,界面型事物有帮助,不能并行。
  2. python中多线程也是用一个解释器,其开销较多进程小
  3. 何时适合多线程
- 响应式页面
- 委派式工作
- 多用户应用程序
  1. 简单串行实例 P345
  2. 简单多进程 P347
  3. 线程池 Queue P348
  4. 双队列 (待处理que 和 输出que)p351
  5. 处理外部错误 p353
  6. 设置限制(人为制造瓶颈)p356

3. 多进程

每个进程有自己的上下文,不受GIL影响

  1. 使用multiprocessing模块 其中进程间通讯可以使用:p359
- Queue 同threading模块的queue
- Pipe 类似套接字的使用方法 p360
- sharedctypes 共享内存(只适用于ctype基本数据类型,尽量别用)
  1. 使用进程池 可以用 with Pool(12) as pool:的上下文管理模式来做 p362
  2. 可以使用 multiprocessing.dummy 中的Pool 来替代上面的真pool 从而将多进程改成多线程

4. 异步编程

核心就是自己控制释放资源的时间

  1. 协程 非抢占型的
  2. async 和await async修饰的函数返回一个future型的值(类似生成器) await方法交出程序控制权
  3. 异步实例 p371
  4. 无异步库/方法时候 如何类似异步的运行方法 Executor 和 futures
- 让所需异步运行的方法 在 Threadpoolexecutor 和 Processpoolexecutor 上面运行 然后用将结果用 await修饰 形成异步

5.小结

这里的知识都是Python程序员应该掌握的知识。
运用多个上述方法也是正常的

第十四章 有用的设计模式

1. 创建型模式 (creational patterns)

用于生成 具有特定行为的对象

  1. 单例模式
- 复写 类__new__方法 简单易于理解 容易出错 被继承后有麻烦
- 复写 metaclass 中的 __call__ 方法 常用
- 复写 类实例的.__dict__方法 (博格 borg 或者说教 单态 monostate)
- 最佳实践:**使用模块而非类**   

2. 结构型模式(structural patterns)

有助于特定用例构建代码

  1. 适配器 duck-type
- **接口** 显式的声明ducktype  接口 A 依赖于接口 I B实现接口I 而不是 A依赖于B  
- 使用 zope.interface 包 先定义一个interface 然后 用 @implementer(xxx)的方式来实现接口
- 抽象类ABC (Abstract Base Classes)除了跟上面差不多的接口继承,还可以复写 ABC类的 __subclasshook__方法来改变 isinstance的判断条件。
- 函数注解 类型提示
- collections.abs
  1. 代理模式 之前十二章的那种缓存就是代理 简单的说就是用一个更快 更节省的模式访问外部资源的方式
  2. 外观(facade) 在包级别以上更加简化其内部调用 (在包上面在包一层)

3. 行为模式(behavioral patterns)

  1. 观察者模式 在一个类中维护需要操作的观察者列表,当事件出现时候 向不同的观察者传递相应的参数 p386
  2. 访问者模式
  3. 模板
  4. 小结
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值