摘要:用注釋寫單元測試單元測試是代碼開發環節必不可少的一環,對于定位和代碼質量而言是非常重要的。現在最廣為人知的單元測試框架就是,它借鑒了中成熟的單元測試框架的。
概述
秦人不暇自哀,而后人哀之;后人哀之而不鑒之,亦使后人而復哀后人也! --論面向文檔編程的重要性
如果想看見識一個人寫代碼的功力,注釋其實是區分老司機和小鮮肉的一個顯著的分界線(有沒有觀察到你們公司的領導基本都在開會或者寫文檔),通常情況下老司機的文檔量與代碼量是1:1的比例,而新人往往認為寫完功能模塊就已經可以完成任務了。生產環境中需要面對現實中大量復雜的業務邏輯和數據校驗并與各方對接,文檔質量和代碼質量就被提升到了相同的高度。很多人沒有寫注釋的習慣,大多數不是因為懶惰,一方面是沒有意識到寫文檔的好處,另一方面是不了解這方面的工具。畢竟從管理上依賴于人的主動性是遠不如依賴于工具有效的。本文介紹如何利用Python注釋提升文檔書寫的質量以及效率的小技巧。
Python在實際生產中,機器學習工作現在看起來,白天像是個算法工程師的活,晚上就變成運維+測試了。Python 一直以來也都受到測試工程師和運維工程師的偏愛,下面是幾個經典的注釋活用case。
用注釋寫單元測試:doctest單元測試是代碼開發環節必不可少的一環,對于Bug定位和代碼質量而言是非常重要的。現在最廣為人知的單元測試框架就是Unittest,它借鑒了Java中成熟的單元測試框架的JUnit。即使像Django還對這個框架有特殊的支持,然而在實現Unittest的時候會感覺確實比較啰嗦,setup,teardown...在維護單元測試的時候很多時候感覺力不從心。
一個巧妙的方式可以是通過doctest,用docstring注釋的方式來完成單元測試,由于每個方法def下面都先跟著一段測試用例,然后緊跟著就是代碼正文,這樣一來很方便我們測試現有代碼的質量,另一方面又便于修改。
舉個例子:
def factorial(n): """Return the factorial of n, an exact integer >= 0. >>> [factorial(n) for n in range(6)] [1, 1, 2, 6, 24, 120] >>> factorial(30) 265252859812191058636308480000000 >>> factorial(-1) Traceback (most recent call last): ... ValueError: n must be >= 0 Factorials of floats are OK, but the float must be an exact integer: >>> factorial(30.1) Traceback (most recent call last): ... ValueError: n must be exact integer >>> factorial(30.0) 265252859812191058636308480000000 It must also not be ridiculously large: >>> factorial(1e100) Traceback (most recent call last): ... OverflowError: n too large """ import math if not n >= 0: raise ValueError("n must be >= 0") if math.floor(n) != n: raise ValueError("n must be exact integer") if n+1 == n: # catch a value like 1e300 raise OverflowError("n too large") result = 1 factor = 2 while factor <= n: result *= factor factor += 1 return result if __name__ == "__main__": import doctest doctest.testmod()
上面是官網提供的一個求N的階乘函數示例,在docstring 中通過 >>>符號來開始一個單元測試,之后換行輸入預期結果即可。實際上就是復制粘貼一下調試過程和結果,真的再簡單不過了,想實現TDD也因此變得非常輕松。
用注釋寫API文檔:apidoc在我們完成機器學習模型后,想要提供一個對外服務的接口以貢獻我們的算力時就需要完備的API文檔,也是通過API的調用才能為我們的模型提供源源不斷的校驗數據,對于提升模型效果有非常實際的意義。對大多數人而言調用API來完成開發都是一件比較開心的事情,因為我們可以少做很多工作就可以實現強大功能。然而,當我們需要對外提供API時就要面臨不一樣的考驗了,接口鑒權、接口設計、版本控制、并發問題、日志埋點...這些都是需要面對的新問題,而利用 apidoc 可以很好地解決這些API文檔中常見的諸多問題,相當于通過模板提升了我們的接口設計的能力。
apidoc為Python提供了一種類似于 docstring 的方式來寫API文檔,從語法上看比較類似于 R中的roxygen,都需要用戶以 @xxx 符號作為一個開頭,隨后書寫相關的定義和功能。
舉個例子:
下面是一個API接口的定義方法,最核心的部分就是
路由
GET/POST方法
名稱/分組
參數與調用例子
(這年頭沒有用例的代碼都是耍流氓)
""" @api {get} /user/:id Request User information @apiName GetUser @apiGroup User @apiParam {Number} id Users unique ID. @apiSuccess {String} firstname Firstname of the User. @apiSuccess {String} lastname Lastname of the User. """
我們可以直接擼一個官方示例來學習如何使用apidoc。
首先,下載示例源碼
git clone https://github.com/apidoc/apidoc cd apidoc
然后,安裝 apidoc 組件
sudo npm install apidoc -g
接著,利用官方代碼來制作一個例子,并且訪問即可。
apidoc -i example/ -o output/ -t template/ open output/index.html
幾個參數的含義如下:
-i:input,表示輸入的文件夾
-o:output,表示輸出文件夾
-t:template,表示模板文件,通過替換模板我們可以修改文檔皮膚
在 example 文件夾下,我們需要在apidoc.json 中填寫配置文件,定義文檔的header和footer部分內容,其余的文件會被自動識別出其中的docstring作為API文檔的一部分。
由于apidoc的官方文檔非常簡單清晰,所以這里不過多強調語法。
apidoc 還為我們提供了接口調試的功能,在實際使用的時候要注意:
我們需要一個web server 才可以使用這個接口調試的功能
要注意跨域的問題。
通過版本對比,我們還可以快速排查API接口的變化情況。需要注意的是這個功能要求我們要將歷史的文檔記錄也要保存在該目錄下的文件中,通常我們可以把歷史的注釋輸出到一個特定文件中保存。
總的來說,雖然,API文檔的書寫并不是一件難度非常高的事情,卻能體現系統模塊設計和用戶體驗設計的功力,我們應該對那些無代碼示例,無版本控制的API文檔say no!
用注釋寫命令行接口docopt利用docopt,我們可以在注釋中直接聲明文件的命令行傳入參數,而不需要通過 argvs變量來捕獲輸入值再做判斷,這在調用運維腳本或者若干任務調度腳本的時候尤其管用,極大地提升了CLI的效率。
舉個例子:(此處代碼僅供參考)
"""Usage: fiannceR.py tcp[--timeout= ] fiannceR.py serial [--baud=9600] [--timeout= ] fiannceR.py -h | --help | --version """ from docopt import docopt if __name__ == "__main__": arguments = docopt(__doc__, version="0.1.1rc") print(arguments)
隨后,我們可以在命令行中成功調用
fiannceR.py tcp 0.0.0.0 3838
這里的 arguments 將傳出一個字典對象,以Key-Value的形式將命令行中的輸入值捕獲。
{"--baud": None, "--help": False, "--timeout": None, "--version": False, "-h": False, "總結": "0.0.0.0", " ": "3838", "serial": False, "tcp": True}
如果真的要從數據擼到模型、接口,那么一排注釋的畫面真是美得不敢想象。
"""unitest >>> FinanceR("20161001") 21.01 """ def FinanceR(date): price = get_price(date) return(price) class(BaseHandler): def get(self): """apidoc @api {get} /price/:date 獲取當前價格 @apiName GetPrice @apiGroup Quota @apiParam {Number} date 交易日期 @apiSuccess {String} price """ date = self.get_argument("date",None) try: price = FinanceR(date) self.write({"data":{"price":price},"response":{"message":"success","code":200}}) except Exception as e: self.write({"data":None,"response":{"message":str(e),"code":404}}) """Usage: fiannceR.py tcp[--timeout= ] fiannceR.py serial [--baud=9600] [--timeout= ] fiannceR.py -h | --help | --version """ from docopt import docopt if __name__ == "__main__": arguments = docopt(__doc__, version="0.1.1rc") print(arguments)
歡迎大家留言討論,給出更多應用案例,交流分享。
參考文獻APIDoc
Python 指南:測試你的代碼
doctest
nose is nicer testing for python
tox: standardize testing in Python
Biopython測試框架
Docopt
Sphinx
docopt.R
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/38195.html
摘要:不同的人的路線圖版本會有所不同。尋找答案從一無所知到無所不知如果你在這個過程中多次遇到困難,在知難而退之前努力嘗試解決問題。并不是成為一個全面的開發人員所需要的唯一技能。首先進行一兩個月的學習階段,然后進入一個月的構建階段。 初級開發者學Python容易陷入茫然,面對市面上種類眾多的編程語言和框架,重要的是堅持自己的選擇,宜精不宜雜。本文是一篇指路文,概述了從編程基礎、引導、文檔閱讀、...
摘要:總之,要永遠做個學習者,但不僅僅只做學習者了解并踐行學習實踐階段循環任何創造性學科的學習都可以分兩個階段,學習階段和構建階段,彼此不斷重復。 初級開發者學Python容易陷入茫然,面對市面上種類眾多的編程語言和框架,重要的是堅持自己的選擇,宜精不宜雜。本文是一篇指路文,概述了從編程基礎、引導、文檔閱讀、書籍和視頻、源代碼等學習和積累環節,值得初學者參考。 作為一個開發者,為何要選擇Py...
摘要:前言羅子雄如何成為一名優秀設計師董明偉工程師的入門和進階董明偉基于自己實踐講的知乎為新人提供了很多實用建議,他推薦的羅子雄如何成為一名優秀設計師的演講講的非常好,總結了設計師從入門到提高的優秀實踐。 前言 羅子雄:如何成為一名優秀設計師 董明偉:Python 工程師的入門和進階 董明偉基于自己實踐講的知乎live為Python新人提供了很多實用建議,他推薦的羅子雄:如何成為一名優秀...
摘要:勤學學習效率與效果取決于執行力。這一步學習的正確姿勢是在實踐操作中發掘問題,然后帶著問題找答案。拆分任務將目標分解成具體可執行的學習任務。勤學強大的執行力是學習的根本保障。分享復述檢驗學習成果,提高學習效果的最好方法。 showImg(https://segmentfault.com/img/bVbcPGZ?w=256&h=256); 前段時間和大家一起分享了一篇關于學習方法內容《大牛...
摘要:工程師也用過快速開發面向消費者的網站以響應一日三變的用戶需求。硬件工程師在樹莓派上用來調試一個人臉檢測的功能,以較低的成本完成核心功能的調試。另一方面,通過在任何一個瀏覽器中就可以直接前往服務器現場,不論是一臺甚至是樹莓派。 概述 資深Python工程師可以選擇的編輯器有很多,比如 Rodeo,Spider,Eclipse,Vim,Visual Studio,Atom,Sublime ...
閱讀 2689·2021-10-12 10:12
閱讀 2335·2021-09-02 15:41
閱讀 2561·2019-08-30 15:55
閱讀 1399·2019-08-30 13:05
閱讀 2430·2019-08-29 11:21
閱讀 3535·2019-08-28 17:53
閱讀 3022·2019-08-26 13:39
閱讀 801·2019-08-26 11:50