From 4fb3bf7b4a9638ce7d69cb4bde6bcfaf543710c2 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Sun, 12 Jun 2016 19:51:46 +0800 Subject: [PATCH 1/4] Wrote a bit about docstrings --- docs/writing/documentation.rst | 120 +++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/docs/writing/documentation.rst b/docs/writing/documentation.rst index bd59437e8..cb541e13c 100644 --- a/docs/writing/documentation.rst +++ b/docs/writing/documentation.rst @@ -65,6 +65,11 @@ There is also **great**, **free** hosting for your Sphinx_ docs: your source repository so that rebuilding your documentation will happen automatically. +When run, Sphinx_ will import your code and using Python's introspection +features it will extract all function, method and class signatures. It will +also extract the accompanying docstrings, and compile it all into well +structured and easily readable documentation for your project. + .. note:: Sphinx is famous for its API generation, but it also works well @@ -127,6 +132,30 @@ Some tools use docstrings to embed more-than-documentation behavior, such as unit test logic. Those can be nice, but you won't ever go wrong with vanilla "here's what this does." +Tools like Sphinx_ will parse your docstrings as reStructuredText and render it +correctly as HTML. This makes it very easy to embed snippets of example code in +a project's documentation. + +Additionally, Doctest_ will read all embedded docstrings that look like input +from the Python commandline (prefixed with ">>>") and run them, checking to see +if the output of the command matches the text on the following line. This +allows developers to embed real examples and usage of functions alongside +their source code, and as a side effect, it also ensures that their code is +tested and works. + +:: + + def my_function(a, b): + """ + >>> my_function(2, 3) + 6 + >>> my_function('a', 3) + 'aaa' + """ + return a * b + +.. _Doctest: https://docs.python.org/3/library/doctest.html + Docstrings versus Block comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -141,8 +170,99 @@ comment block is a programmer's note. The docstring describes the """Returns the square root of self times self.""" ... +Unlike block comments, docstrings are built into the Python language itself. +This means you can use all of Python's powerful introspection capabilities to +access docstrings at runtime, compared with comments which are optimised out. +Docstrings are accessible from both the `__doc__` dunder attribute for almost +every Python object, as well as with the built in `help()` function. + +While block comments are usually used to explain *what* a section of code is +doing, or the specifics of an algorithm, docstrings are more intended for +explaining to other users of your code (or you in 6 months time) *how* a +particular function can be used and the general purpose of a function, class, +or module. + +Writing Docstrings +~~~~~~~~~~~~~~~~~~ + +Depending on the complexity of the function, method, or class being written, a +one-line docstring may be perfectly appropriate. These are generally used for +really obvious cases, such as:: + + def add(a, b): + """Add two numbers and return the result.""" + return a + b + +The docstring should describe the function in a way that is easy to understand. +Embedding the function's signature in the docstring is unnecessary because it +can easily be obtained using the `inspect` module, and doesn't provide much +additional information. + +For more complex cases, there are a couple generally accepted styles used +when writing documentation. The first of these uses reStructuredText syntax +to format arguments and other elements of the docstring appropriately:: + + def function1(self, arg1, arg2, arg3): + """A short, one line summary of the function. + + This is a longer explanation, which may include math with + latex syntax :math:`\\alpha`. + + :param arg1: the first value + :param arg2: the first value + :param arg3: the first value + :type arg1: int, float,... + :type arg2: int, float,... + :type arg3: int, float,... + :returns: arg1/arg2 +arg3 + :rtype: int, float + """ + return arg1/arg2 + arg3 + +`thomas-cokelaer.info`_ has a fairly complete article showing more examples for +this style. + +While the end result is parsed by Sphinx and renders correctly in a browser, it +isn't the easiest of formats to read. The `NumPy style`_ is a lot nicer to read, +however it consumes a lot more real estate than the previous style:: + + def random_number_generator(arg1, arg2): + """ + Summary line. + + Extended description of function. + + Parameters + ---------- + arg1 : int + Description of arg1 + arg2 : str + Description of arg2 + + Returns + ------- + int + Description of return value + + """ + return 42 + +The `sphinx.ext.napoleon`_ plugin allows Sphinx to parse this style of +docstrings, making it easy to incorporate NumPy style docstrings into your +project. + +At the end of the day, it doesn't really matter what style is used for writing +docstrings, their purpose is to serve as documentation for anyone who may need +to read or make changes to your code. As long as it is correct, understandable +and gets the relevant points across then it has done the job it was designed to +do. + + .. see also:: Further reading on docstrings: :pep:`257` +.. _thomas-cokelaer.info: http://thomas-cokelaer.info/tutorials/sphinx/docstring_python.html +.. _sphinx.ext.napoleon: https://sphinxcontrib-napoleon.readthedocs.io/ +.. _`NumPy style`: http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html Other Tools ----------- From fb388b8f7bffabc728b1a90178eed16515f61585 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Sun, 12 Jun 2016 19:53:40 +0800 Subject: [PATCH 2/4] changed the pep 257 line from a see also to a normal line --- docs/writing/documentation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/writing/documentation.rst b/docs/writing/documentation.rst index cb541e13c..036868167 100644 --- a/docs/writing/documentation.rst +++ b/docs/writing/documentation.rst @@ -258,7 +258,7 @@ and gets the relevant points across then it has done the job it was designed to do. -.. see also:: Further reading on docstrings: :pep:`257` +For further reading on docstrings, feel free to consult :pep:`257` .. _thomas-cokelaer.info: http://thomas-cokelaer.info/tutorials/sphinx/docstring_python.html .. _sphinx.ext.napoleon: https://sphinxcontrib-napoleon.readthedocs.io/ From 3c0b0270baad77a813bf1dedb5674ba159f966d1 Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Mon, 13 Jun 2016 09:49:18 +0800 Subject: [PATCH 3/4] Removed the rst/sphinx-style docstring example --- docs/writing/documentation.rst | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/docs/writing/documentation.rst b/docs/writing/documentation.rst index 036868167..c5f822197 100644 --- a/docs/writing/documentation.rst +++ b/docs/writing/documentation.rst @@ -198,33 +198,10 @@ Embedding the function's signature in the docstring is unnecessary because it can easily be obtained using the `inspect` module, and doesn't provide much additional information. -For more complex cases, there are a couple generally accepted styles used -when writing documentation. The first of these uses reStructuredText syntax -to format arguments and other elements of the docstring appropriately:: - - def function1(self, arg1, arg2, arg3): - """A short, one line summary of the function. - - This is a longer explanation, which may include math with - latex syntax :math:`\\alpha`. - - :param arg1: the first value - :param arg2: the first value - :param arg3: the first value - :type arg1: int, float,... - :type arg2: int, float,... - :type arg3: int, float,... - :returns: arg1/arg2 +arg3 - :rtype: int, float - """ - return arg1/arg2 + arg3 - -`thomas-cokelaer.info`_ has a fairly complete article showing more examples for -this style. - -While the end result is parsed by Sphinx and renders correctly in a browser, it -isn't the easiest of formats to read. The `NumPy style`_ is a lot nicer to read, -however it consumes a lot more real estate than the previous style:: +For more detailed documentation of code a popular style is the one used for the +Numpy project, often called `Numpy style`_ docstrings. While it can take up a +few more lines than usual, it allows the developer to include a lot more +information about a method, function, or class. :: def random_number_generator(arg1, arg2): """ From 10defd73a2f1cb34887f178dc119c32c2dbbba8d Mon Sep 17 00:00:00 2001 From: Michael Bryan Date: Mon, 13 Jun 2016 10:07:29 +0800 Subject: [PATCH 4/4] Added a bit so the transition from short to long docstrings flows better --- docs/writing/documentation.rst | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/writing/documentation.rst b/docs/writing/documentation.rst index c5f822197..b15935179 100644 --- a/docs/writing/documentation.rst +++ b/docs/writing/documentation.rst @@ -194,14 +194,20 @@ really obvious cases, such as:: return a + b The docstring should describe the function in a way that is easy to understand. -Embedding the function's signature in the docstring is unnecessary because it -can easily be obtained using the `inspect` module, and doesn't provide much -additional information. +For simple cases like trivial functions and classes, simply embedding the +function's signature (i.e. `add(a, b) -> result`) in the docstring is +unnecessary. This is because with Python's `inspect` module, it is already +quite easy to find this information if needed, and it is also readily available +by reading the source code. + +In larger or more complex projects however, it is often a good idea to give +more information about a function, what it does, any exceptions it may raise, +what it returns, or relevant details about the parameters. For more detailed documentation of code a popular style is the one used for the Numpy project, often called `Numpy style`_ docstrings. While it can take up a -few more lines than usual, it allows the developer to include a lot more -information about a method, function, or class. :: +few more lines the previous example, it allows the developer to include a lot +more information about a method, function, or class. :: def random_number_generator(arg1, arg2): """