很多时候看别人代码,发现注释挺有风格,还挺统一,其实不但是为了方便读,更是为了方便自动生成文档。
毕竟,在代码堆里翻来覆去看注释也不太方便,在PDF或者HTML格式文档里面看更加方便、灵活。
epydoc
专门用于Python代码里面自动生成文档,而 doxygen
则广泛用于C++、Java、Python等代码里面自动生成文档。
当然,还有一个 Sphinx
,但这个还是比较适合于写用户手册,不太熟悉,自己写用户手册一般使用 Org-Mode
。
通过注释、文档嵌入代码的方式,既保持了文档能够及时更新,也方便维护。
这次的关注重点是 epydoc
。
epydoc
是根据Python代码里面注释生成API文档的工具。
下载源码 https://pypi.python.org/pypi/epydoc 进行安装:
$ cd epydoc-3.0.1$ sudo python setup.py install$ epydoc --help$ epydocgui
为epydoc模块生成html文档,保存于doc目录:
$ epydoc --html epydoc -o doc$ epydoc --html epydoc/gui.py -o HTML
生成PDF文档:
$ epydoc -v -o PDF --pdf --name "Epydoc" epydoc/
检查文档信息:
$ epydoc --check epydoc/gui.py
epydoc
可以通过 --config
指定配置文件,配置文件举例:
[epydoc] # Epydoc section marker (required by ConfigParser)# Information about the project.name: My Cool Projecturl: http://cool.project/# The list of modules to document. Modules can be named using# dotted names, module filenames, or package directory names.# This option may be repeated.modules: sys, os.path, remodules: my/project/driver.py# Write html output to the directory "apidocs"output: htmltarget: apidocs/# Include all automatically generated graphs. These graphs are# generated using Graphviz dot.graph: alldotpath: /usr/local/bin/dot
epydoc
支持的被标记的文档叫 epytext
,这是Python文档字符串中的一种轻量级标记语言。
对于段落的要求就是 左对齐
,左对齐的数行文本就是一个段落,举例:
Rendered Outputdef example(): """ This is a paragraph. Paragraphs can span multiple lines, and can contain I{inline markup}. This is another paragraph. Paragraphs are separated by blank lines. """ [...]
对于列表,分为排序和非排序,如果是排序则用 数字
开头,如果是非排序,则用 -
开头。
同时,在内容上要有一定的 缩进
,这样才能形成有层次的列表, 举例:
def example(): """ 1. This is an ordered list item. 2. This is a another ordered list item. 3. This is a third list item. Note that the paragraph may be indented more than the bullet. """ [...]def example(): """ This is a paragraph. 1. This is a list item. 2. This a second list item. - This is a sublist """ [...]def example(): """ This is a paragraph. 1. This is a list item. - This is a sublist. - The sublist contains two items. - The second item of the sublist has its own sublist. 2. This list item contains two paragraphs and a doctest block. >>> print 'This is a doctest block' This is a doctest block This is the second paragraph. """ [...]
另外, epytext
遇到数字或者 -
就会看做列表处理,如果要当成普通文本,则:
不要在开头或者转义字符
章节依次下降:
=======-------
~~~~~~~
举例:
def example(): """ This paragraph is not in any section. Section 1 ========= This is a paragraph in section 1. Section 1.1 ----------- This is a paragraph in section 1.1. Section 1.1.1 ~~~~~~~~~~~~~ This is a paragraph in section 1.1.1 Section 2 ========= This is a paragraph in section 2. """
对于在 ::
之后的文本是文本块,不会进行标记,直接显示内容:
def example(): """ The following is a literal block:: Literal / / Block This is a paragraph following the literal block. """ [...]
注意 文本块
内容是有一定的缩进的,否则会报错。
doctest文档是可以模块 doctest
进行测试运行的内容,一般是在python解释器里面的操作内容:
def example(): """ The following is a doctest block: >>> print (1+3, ... 3+5) (4, 8) >>> 'a-b-c-d-e'.split('-') ['a', 'b', 'c', 'd', 'e'] This is a paragraph following the doctest block. """
针对具体的类、变量等文档标记:
def example(): """ @param x: This is a description of the parameter x to a function. Note that the description is indented four spaces. @type x: This is a description of x's type. @return: This is a description of the function's return value. It contains two paragraphs. """
更多标记参考: http://www.ast.cam.ac.uk/~rgm/dazle/software/dics/src/epydoc-3.0alpha2/doc/fields.html#fields
Function docstrings
:
Variables (module or class docstrings)
:
Properties (property docstrings)
:
Grouping and Sorting (module, class, function, or method docstrings)
:
Related Topics
:
Notes and Warnings
:
Status
:
Formal Conditions
:
Bibliographic Information
:
Summarization
:
I{...}
: 斜体B{...}
: 粗体C{...}
: 代码M{...}
: 数学表达式
举例:
Docstring InputRendered Outputdef example(): """ I{B{Inline markup} may be nested; and it may span} multiple lines. - I{Italicized text} - B{Bold-faced text} - C{Source code} - M{Math} Without the capital letter, matching braces are not interpreted as markup: C{my_dict={1:2, 3:4}}. """
URLs
以 U{text<url>}
的形式创建网页链接:
def example(): """ - U{www.python.org} - U{http://www.python.org} - U{The epydoc homepage<http://epydoc.sourceforge.net>} - U{The B{I{Python}} homepage<www.python.org>} - U{Edward Loper<mailto:edloper@gradient.cis.upenn.edu>} """
内部引用链接
以 L{text<object>}
的形式创建内部引用链接,引用的可以是Python对象:
def example(): """ - L{x_transform} - L{search<re.search>} - L{The I{x-transform} function <x_transform>} """
索引
以 X{...}
的形式建立索引:
def example(): """ An X{index term} is a term that should be included in the index. """
特殊符号
以 S{code}
的形式嵌入特殊符号:
def example(): """ Symbols can be used in equations: - S{sum}S{alpha}/x S{<=} S{beta} S{<-} and S{larr} both give left arrows. Some other arrows are S{rarr}, S{uarr}, and S{darr}. """
转义特殊字符
有些字符是被 epytext
当作标记命令的,如果需要显示其本意,则进行转义:
def example(): """ This paragraph ends with two colons, but does not introduce a literal blockE{:}E{:} E{-} This is not a list item. Escapes can be used to write unmatched curly braces: E{rb}E{lb} """
这里以 E{xxx}
的形式转义,其中 E{rb}
表示 }
, 而 E{lb}
表示 {
.
图片
以 G{graphtype args...}
的形式引入自动生成的图片,比如类派生关系图等:
参考: http://www.ast.cam.ac.uk/~rgm/dazle/software/dics/src/epydoc-3.0alpha2/doc/relatedprojects.html
主要有:
pydoceasydocdoc.pydoxygenjavadoc
#!/usr/bin/env python## objdoc: epydoc command-line interface# Edward Loper## Created [03/15/02 10:31 PM]# $Id: gui.py 646 2004-03-19 19:01:37Z edloper $#"""Graphical interface to epydoc. This interface might be useful forsystems where it's inconvenient to use the command-line interface(such as Windows). It supports many (but not all) of the featuresthat are supported by the command-line interface. It also supportsloading and saving of X{project files}, which store a set of relatedmodules, and the options that should be used to generate thedocumentation for those modules.Usage:: epydocgui [OPTIONS] [FILE.prj | MODULES...] FILE.prj An epydoc GUI project file. MODULES... A list of Python modules to document. -V, --version Print the version of epydoc. -h, -?, --help, --usage Display this usage message --debug Do not suppress error messages@todo: Use ini-style project files, rather than pickles (using thesame format as the CLI)."""__docformat__ = 'epytext en'#.....def document(options, cancel, done): """ Create the documentation for C{modules}, using the options specified by C{options}. C{document} is designed to be started in its own thread by L{EpydocGUI._go}. @param options: The options to use for generating documentation. This includes keyword options that can be given to L{docwriter.html.HTMLWriter}, as well as the option C{target}, which controls where the output is written to. @type options: C{dictionary} """#.....
和 javadoc
类似,doxygen也是将文档嵌入代码中的,支持导出的文件格式:
HTMLCHMRTFPDFLaTeXman page等
使用doxygen生成文档的开源项目参考:
http://xerces.apache.org/xerces-c/apiDocs-3/classes.htmlC++ Sockets Library: http://www.alhem.net/Sockets/cocos2d: http://www.cocos2d-swift.org/
/** * <A short one line description> * * <Longer description> * <May span multiple lines or paragraphs as needed> * * @param Description of method's or function's input parameter * @param ... * @return Description of the return value */
doxygen支持多种注释风格,这里 @param
表示参数, @return
表示返回值,遵循一定的格式即可。
/** * @file * @author John Doe <jdoe@example.com> * @version 1.0 * * @section LICENSE * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details at * http://www.gnu.org/copyleft/gpl.html * * @section DESCRIPTION * * The time class represents a moment of time. */class Time { public: /** * Constructor that sets the time to a given value. * * @param timemillis Number of milliseconds * passed since Jan 1, 1970. */ Time (int timemillis) { // the code } /** * Get the current time. * * @return A time object set to the current time. */ static Time now () { // the code }};
良好的注释符,不但方便生成准确的文档,也使得简洁明了。
从http://www.doxygen.org/download.html 下载相应平台源码,进行安装即可:
$ git clone https://github.com/doxygen/doxygen.git$ cd doxygen$ ./configure$ make$ make install$ doxygen --help
$ doxygen -g [config_file_name]
也可以更新已有配置文件:
$ doxygen -u [config_file_name]
直接使用已有配置文件:
$ doxygen [config_file_name]
在第二步就已经生成了文档,默认是HTML格式,一切根据配置文件来生成。
为了和代码本身的注释有所区别,会在注释里面添加一些标志,但存在多种风格。
/** * ... text ... */
/*! * ... text ... *///!//!... text ...//!////// ... text ...///
int var; /*!< Detailed description after the member */int var; /**< Detailed description after the member */int var; //!< Detailed description after the memberint var; ///< Detailed description after the member
注意不能少了 <
符号.
/*! A test class */class Test{ public: /** An enum type. * The documentation block cannot be put after the enum! */ enum EnumType { int EVal1, /**< enum value 1 */ int EVal2 /**< enum value 2 */ }; void member(); //!< a member function. protected: int value; /*!< an integer value */};/////////////////////////////////////////////////////////** * A test class. A more elaborate class description. */class Test{ public: /** * An enum. * More detailed enum description. */ enum TEnum { TVal1, /**< enum value TVal1. */ TVal2, /**< enum value TVal2. */ TVal3 /**< enum value TVal3. */ } *enumPtr, /**< enum pointer. Details. */ enumVar; /**< enum variable. Details. */ /** * A constructor. * A more elaborate description of the constructor. */ Test(); /** * A destructor. * A more elaborate description of the destructor. */ ~Test(); /** * a normal member taking two arguments and returning an integer value. * @param a an integer argument. * @param s a constant character pointer. * @see Test() * @see ~Test() * @see testMeToo() * @see publicVar() * @return The test results */ int testMe(int a,const char *s); /** * A pure virtual member. * @see testMe() * @param c1 the first argument. * @param c2 the second argument. */ virtual void testMeToo(char c1,char c2) = 0; /** * a public variable. * Details. */ int publicVar; /** * a function variable. * Details. */ int (*handler)(int a,int b);};
doxygen的文档很详细,支持的标记命令也很多: http://www.stack.nl/~dimitri/doxygen/manual/commands.html#cmdparam
听了很多道理,依旧过不好这一生;学了很多文档标记,依旧写不好文档。
作者简介:
朱春来(Leslie Zhu),金融工程师,毕业于西安电子科技大学, 喜欢历史,喜欢编程. 日常在GNU/Linux环境下进行C/C++、Python开发,对Common Lisp、Node.js、金融等感兴趣。可以通过邮箱(pythonisland@gmail.com)联系他,或者直接在他的个人主页上留言.
访问朱春来(Leslie Zhu)的个人主页(http://lesliezhu.github.com)