天天看點

《Python進階程式設計》(第二版) ——速查筆記 第10~14章 完結第十章 測試驅動開發 TDD test-driven Development第十一章 優化 一般分析原則與分析技術第十二章 優化 一些強大的技術第十三章 并發第十四章 有用的設計模式

《Python進階程式設計》(第二版) ——速查筆記 第10~14章 完結

  • 第十章 測試驅動開發 TDD test-driven Development
    • 1. 簡單的測試介紹
    • 2.測試的提高部分
    • 3.小結
  • 第十一章 優化 一般分析原則與分析技術
    • 1. 3個優化原則
    • 2. 優化政策
    • 3. 查找瓶頸
  • 第十二章 優化 一些強大的技術
    • 1. 降低複雜度
    • 2. 簡化
    • 3. 使用集合子產品
    • 4. 架構體系的權衡
    • 5. 緩存
    • 6. 小結
  • 第十三章 并發
    • 1. 為何需要并發
    • 2. 多線程
    • 3. 多程序
    • 4. 異步程式設計
    • 5.小結
  • 第十四章 有用的設計模式
    • 1. 建立型模式 (creational patterns)
    • 2. 結構型模式(structural patterns)
    • 3. 行為模式(behavioral patterns)

第十章 測試驅動開發 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. 小結