Python

在实际生产中,机器学习工作现在看起来,白天像是个算法工程师的活,晚上就变成运维+测试了。Python 一直以来也都受到测试工程师和运维工程师的偏爱,下面是几个经典的注释活用case。

用注释写单元测试:doctest

单元测试是代码开发环节必不可少的一环,对于Bug定位和代码质量而言是非常重要的。现在最广为人知的单元测试框架就是Unittest,它借鉴了Java中成熟的单元测试框架的JUnit。即使像Django还对这个框架有特殊的支持,然而在实现Unittest的时候会感觉确实比较啰嗦,setup,teardown…在维护单元测试的时候很多时候感觉力不从心。

一个巧妙的方式可以是通过doctest,用docstring注释的方式来完成单元测试,由于每个方法def下面都先跟着一段测试用例,然后紧跟着就是代码正文,这样一来很方便我们测试现有代码的质量,另一方面又便于修改。

举个例子:

deffactorial(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

"""

importmath

ifnotn>=0:

raiseValueError("n must be >= 0")

ifmath.floor(n)!=n:

raiseValueError("n must be exact integer")

ifn+1==n:# catch a value like 1e300

raiseOverflowError("n too large")

result=1

factor=2

whilefactor<=n:

result*=factor

factor+=1

returnresult

if__name__=="__main__":

importdoctest

doctest.testmod()

deffactorial(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

"""

importmath

ifnotn>=0:

raiseValueError("n must be >= 0")

ifmath.floor(n)!=n:

raiseValueError("n must be exact integer")

ifn+1==n:# catch a value like 1e300

raiseOverflowError("n too large")

result=1

factor=2

whilefactor<=n:

result*=factor

factor+=1

returnresult

if__name__=="__main__":

importdoctest

doctest.testmod()

上面是官网提供的一个求N的阶乘函数示例,在docstring 中通过 >>>符号来开始一个单元测试,之后换行输入预期结果即可。实际上就是复制粘贴一下调试过程和结果,真的再简单不过了,想实现TDD也因此变得非常轻松。

用注释写API文档:apidoc

在我们完成机器学习模型后,想要提供一个对外服务的接口以贡献我们的算力时就需要完备的API文档,也是通过API的调用才能为我们的模型提供源源不断的校验数据,对于提升模型效果有非常实际的意义。对大多数人而言调用API来完成开发都是一件比较开心的事情,因为我们可以少做很多工作就可以实现强大功能。然而,当我们需要对外提供API时就要面临不一样的考验了,接口鉴权、接口设计、版本控制、并发问题、日志埋点…这些都是需要面对的新问题,而利用 apidoc 可以很好地解决这些API文档中常见的诸多问题,相当于通过模板提升了我们的接口设计的能力。

apidoc为Python提供了一种类似于 docstring 的方式来写API文档,从语法上看比较类似于 R中的roxygen,都需要用户以 @xxx 符号作为一个开头,随后书写相关的定义和功能。

举个例子:

下面是一个API接口的定义方法,最核心的部分就是

路由

GET/POST方法

名称/分组

参数与调用例子

路由

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.

"""

"""

@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 clonehttps://github.com/apidoc/apidoc

cdapidoc

git clonehttps://github.com/apidoc/apidoc

cdapidoc

然后,安装 apidoc 组件

sudo npm install apidoc -g

sudo npm install apidoc -g

接着,利用官方代码来制作一个例子,并且访问即可。

apidoc-iexample/ -ooutput/ -ttemplate/

openoutput/index.html

apidoc-iexample/ -ooutput/ -ttemplate/

openoutput/index.html

几个参数的含义如下:

-i:input,表示输入的文件夹

-o:output,表示输出文件夹

-t:template,表示模板文件,通过替换模板我们可以修改文档皮肤

-i:input,表示输入的文件夹

-o:output,表示输出文件夹

-t:template,表示模板文件,通过替换模板我们可以修改文档皮肤

在 example 文件夹下,我们需要在apidoc.json 中填写配置文件,定义文档的header和footer部分内容,其余的文件会被自动识别出其中的docstring作为API文档的一部分。

由于apidoc的官方文档非常简单清晰,所以这里不过多强调语法。

apidoc 还为我们提供了接口调试的功能,在实际使用的时候要注意:

我们需要一个web server 才可以使用这个接口调试的功能

要注意跨域的问题。

我们需要一个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

"""

fromdocoptimportdocopt

if__name__=='__main__':

arguments=docopt(__doc__,version='0.1.1rc')

print(arguments)

"""Usage:

fiannceR.py tcp [--timeout=]

fiannceR.py serial [--baud=9600] [--timeout=]

fiannceR.py -h | --help | --version

"""

fromdocoptimportdocopt

if__name__=='__main__':

arguments=docopt(__doc__,version='0.1.1rc')

print(arguments)

随后,我们可以在命令行中成功调用

fiannceR.py tcp 0.0.0.0 3838

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}

{'--baud':None,

'--help':False,

'--timeout':None,

'--version':False,

'-h':False,

'':'0.0.0.0',

'':'3838',

'serial':False,

'tcp':True}

总结

如果真的要从数据撸到模型、接口,那么一排注释的画面真是美得不敢想象。

"""unitest

>>> FinanceR('20161001')

21.01

"""

defFinanceR(date):

price=get_price(date)

return(price)

class(BaseHandler):

defget(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}})

exceptExceptionase:

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

"""

fromdocoptimportdocopt

if__name__=='__main__':

arguments=docopt(__doc__,version='0.1.1rc')

print(arguments)

"""unitest

>>> FinanceR('20161001')

21.01

"""

defFinanceR(date):

price=get_price(date)

return(price)

class(BaseHandler):

defget(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}})

exceptExceptionase:

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

"""

fromdocoptimportdocopt

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

Sphinxdocopt.R

APIDoc

Python 指南:测试你的代码

doctest

nose is nicer testing for python

tox: standardize testing in Python

Biopython测试框架

Docopt

Sphinxdocopt.R

手机python编程文件如何转文档_Python 开发者面向文档编程的正确姿势相关推荐

  1. python 读取文件到字典读取顺序_python顺序的读取文件夹下名称有序的文件方法...

    python顺序的读取文件夹下名称有序的文件方法 如下所示: import os path="/home/test/" #待读取的文件夹 path_list=os.listdir( ...

  2. python下载文件的11种方式_Python下载文件的11种方式

    在本教程中,你将学习如何使用不同的Python模块从web下载文件.此外,你将下载常规文件.web页面.Amazon S3和其他资源. 最后,你将学习如何克服可能遇到的各种挑战,例如下载重定向的文件. ...

  3. python中文件的打开与关闭_python中的文件打开与关闭操作命令介绍

    python中的文件打开与关闭操作命令介绍 1.文件打开与关闭 在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件 open(文件名,访问模式). f = open('t ...

  4. python读取文件的三种方式_python中读取文件的f.seek()方法

    用于二进制文件中 F.seek方法 作用: 设置读写位置 F.seek(偏移量, whence=相对位置) 偏移量 大于0的数代表向文件末尾方向移动的字节数 小于0的数代表向文件头方向中移动的字节数 ...

  5. python对文件追加内容的方法_Python实现文件内容批量追加的方法示例

    本文实例讲述了Python实现文件内容批量追加的方法.分享给大家供大家参考,具体如下: #coding:utf-8 import os #-------代码段一 #获取当前文件夹 filePath = ...

  6. python的文件读写方法有哪些_python读写文件的方法有哪些

    python读写文件的方法有哪些 发布时间:2020-08-07 11:58:05 来源:亿速云 阅读:87 作者:小新 这篇文章主要介绍python读写文件的方法有哪些,文中介绍的非常详细,具有一定 ...

  7. 不是python对文件的读操作方法的是-一文读懂Python对文件的各种操作方式-阿里云开发者社区...

    文件操作:Python中的文件对象不仅可以用来访问普通的磁盘文件,而且也可以访问任何其它类型抽象层面上的"文件". 通过Python程序来对计算机中的各种文件进行增删改查的操作,也 ...

  8. 用python读取文档_python读取word文档

    word.Quit() 这种方式产生的text文档,不能用python用普通的r方式读取,为了让python可以用r方式读取,应当写成 doc.SaveAs('c:/test', 4) 注意:系统执行 ...

  9. python遍历文件夹下所有文件大小_python遍历文件夹——两种遍历本地文件记录文件夹个数、文件数及文件大小的方法...

    这两个函数的功能:得到给定目录的文件夹个数.文件数,以及文件大小 walkFolders函数没有用到os.walk函数,是自己递归调用的:walkfunc函数用到了os.walk函数,方便了很多. i ...

最新文章

  1. pygame的字体画不出来_5毛钱的圆珠笔画的?每一幅都是大师之作,网友:为何我画不出来...
  2. Android Studio上手,基于VideoView的本地文件及流媒体播放器
  3. 原生js获取css样式
  4. java、前端、php、asp.net开发资源分享(视频教程,源码,项目)
  5. Bootstrap4+MySQL前后端综合实训-Day02-AM【Bootstrap4(入门、环境搭建、文字排版、颜色、表格、图片、进度条、折叠、输入框组、模态框)、Font Awesome字体图标】
  6. 操作系统中的多级队列调度
  7. 前端学习(769):new关键字执行过程
  8. 【Java】总结Java数组的拷贝和输出
  9. java 注销变量_[ Java学习基础 ] Java对象的创建和销毁
  10. php删除更新修改时间,php怎样获取文件的最后修改时间
  11. Hdu2680 最短路
  12. 【Anychat】理解POCO
  13. Golang 接口相等比较注意要点
  14. 渗透测试中linux常用命令
  15. p51 thinkpad 拆解_ThinkPad P51值得买吗?联想ThinkPad P51移动工作站图解评测
  16. 股价大涨61%,趣头条还能维持下一季增长吗?
  17. Xcelsius2008系统
  18. 音视频基础知识|ANS 噪声抑制原理解析
  19. seaweedfs springboot 文件名乱码
  20. android app自动卸载,无需ROOT 只需2招解决Android手机无法卸载的流氓APP

热门文章

  1. 屏幕阅读器安全吗_如何为屏幕阅读器设计网站布局
  2. 使用Model-View-ViewModel使用Dart Streams使Flutter中的代码更清晰
  3. 自制口袋妖怪_承诺和口袋妖怪-我如何学会异步思考
  4. 老公吵架把我扔街上_我是如何从在街上卖食物到为顶尖的技术公司工作的方式-第2部分:获取......
  5. react api_如何在WordPress REST API之上构建React应用
  6. node.js ejs_如何在Node.js应用程序中使用EJS模板
  7. C语言:斗地主发牌程序
  8. Java多线程:静态代理模式
  9. 一篇夯实一个知识点系列--python实现十大排序算法
  10. Python高级——闭包与装饰器