Yes, you only need the type hints OR the annotations in the Args and Returns, not both.
References
According to the Google Python Style Guide: "The description should include required type(s) if the code does not contain a corresponding type annotation."
The Sphinx Docs also encourage this in their example code:
def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
"""Example function with PEP 484 type annotations.
Args:
param1: The first parameter.
param2: The second parameter.
Returns:
The return value. True for success, False otherwise.
"""
Answer from Kris Gesling on Stack Overflowpython - Type annotations with google style docstrings - Stack Overflow
My thoughts on docstrings, pdoc and Google style vs. Markdown
coding style - What are the most common Python docstring formats? - Stack Overflow
documentation - Python Google-Style DocString for Function with No Arguments - Stack Overflow
Videos
Yes, you only need the type hints OR the annotations in the Args and Returns, not both.
References
According to the Google Python Style Guide: "The description should include required type(s) if the code does not contain a corresponding type annotation."
The Sphinx Docs also encourage this in their example code:
def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
"""Example function with PEP 484 type annotations.
Args:
param1: The first parameter.
param2: The second parameter.
Returns:
The return value. True for success, False otherwise.
"""
This is very much IMHO, but I don't think enumerating all the parameters in the docstring has a lot of value if you have decent names and type annotations.
def sum(a: int, b: int) -> int:
"""Returns the result of adding the inputs together."""
return a + b
is more than adequately clear IMO. In real life with this specific example I'd probably do:
def sum(a: int, b: int) -> int:
"""Does exactly what it says."""
return a + b
Since the parameters are two ints, the result is another int, and the name of the function is sum which is a perfectly ordinary English word that means "the thing you get when you add other things together", I don't think any further explanation is necessary (other than perhaps a confirmation that this isn't a trick).
So, I wanted to add some API documentation to my project. Unfortunately, there are many competing standards/styles and many tools to generate HTML documentation.
Initially I chose pdoc, as it seems simple, does the job well and requires zero configuration. So far, so good. The problem is that is doesn't FULLY support ANY of the most popular docstring standards - ReStructuredText, Google, NumPy; instead, it uses its own style based on Markdown. I actually find it nice & clean, because:
-
you don't need to specify variable/attribute/arg types if you already have type hints in your code
-
you document instance/class variables right after they are declared (not in class docstring)
-
similarly, you document
_init__constructor right after it is declared, not in the class docstring
The problem is that - besides pdoc itself - no one really recognizes its Markdown standard. It's not supported by PyCharm, pyment, pymend, nor by other tools.
However! According to Sphinx/Napoleon Example Google Style Python Docstrings, it is totally possible to use the Google docstrings style in a similar way - i.e, the 3 bullet points above would still work!
So, I could simply use Google style (which is a recognized standard) in a way I would use pdoc's Markdown. The only thing to make sure is not to use the Attributes: and Methods: sections in class docstring, as it would appear as duplicate in generated HTML. I would still use sections Args: Returns: Yields: and Raises: in function docstrings, where applicable.
And my commandline to run pdoc would be:
pdoc modulename -o docs --docformat google --no-show-source
What do you guys think?
PS. One minor downside of placing docstrings after variable declarations is that they do NOT become __doc__, as they do in the case of modules, classes and functions. So, these comments would not be discoverable programmatically (or interactively via help()). But I guess it doesn't matter that much...
Formats
Python docstrings can be written following several formats as the other posts showed. However the default Sphinx docstring format was not mentioned and is based on reStructuredText (reST). You can get some information about the main formats in this blog post.
Note that the reST is recommended by the PEP 287
There follows the main used formats for docstrings.
- Epytext
Historically a javadoc like style was prevalent, so it was taken as a base for Epydoc (with the called Epytext format) to generate documentation.
Example:
"""
This is a javadoc style.
@param param1: this is a first param
@param param2: this is a second param
@return: this is a description of what is returned
@raise keyError: raises an exception
"""
- reST
Nowadays, the probably more prevalent format is the reStructuredText (reST) format that is used by Sphinx to generate documentation. Note: it is used by default in JetBrains PyCharm (type triple quotes after defining a method and hit enter). It is also used by default as output format in Pyment.
Example:
"""
This is a reST style.
:param param1: this is a first param
:param param2: this is a second param
:returns: this is a description of what is returned
:raises keyError: raises an exception
"""
Google has their own format that is often used. It also can be interpreted by Sphinx (ie. using Napoleon plugin).
Example:
"""
This is an example of Google style.
Args:
param1: This is the first param.
param2: This is a second param.
Returns:
This is a description of what is returned.
Raises:
KeyError: Raises an exception.
"""
Even more examples
- Numpydoc
Note that Numpy recommend to follow their own numpydoc based on Google format and usable by Sphinx.
"""
My numpydoc description of a kind
of very exhautive numpydoc format docstring.
Parameters
----------
first : array_like
the 1st param name `first`
second :
the 2nd param
third : {'value', 'other'}, optional
the 3rd param, by default 'value'
Returns
-------
string
a value in a string
Raises
------
KeyError
when a key error
OtherError
when an other error
"""
Converting/Generating
It is possible to use a tool like Pyment to automatically generate docstrings to a Python project not yet documented, or to convert existing docstrings (can be mixing several formats) from a format to an other one.
Note: The examples are taken from the Pyment documentation
The Google style guide contains an excellent Python style guide. It includes conventions for readable docstring syntax that offers better guidance than PEP-257. For example:
def square_root(n):
"""Calculate the square root of a number.
Args:
n: the number to get the square root of.
Returns:
the square root of n.
Raises:
TypeError: if n is not a number.
ValueError: if n is negative.
"""
pass
I like to extend this to also include type information in the arguments, as described in this Sphinx documentation tutorial. For example:
def add_value(self, value):
"""Add a new value.
Args:
value (str): the value to add.
"""
pass
Package
The code described in the following section have now been made available in a separate package. Please see this repository for details: https://github.com/Xaldew/yasnippet-radical-snippets.
Old Answer
I use the package called yasnippet for something similar to this. After some minor changes I adapted it to use the the Google docstring style instead:

Do note however that it requires some setup:
The snippet itself needs to execute some utility elisp code to generate the text. This is typically solved by creating a file called .yas-setup.el with the code inside the python-mode snippet directory. It is however also possible to place the code somewhere inside your .emacs instead.
The code for the snippet is:
# -*- mode: snippet -*-
# Insert Google style docstring and function definition.
# name: Python Google style Docstring
# key: defg
# type: snippet
# contributor: Xaldew
# --
def ${1:name}($2):
\"\"\"$3
${2:$(python-args-to-google-docstring yas-text t)}
${5:Returns:
$6
}
\"\"\"
${0:$$(let ((beg yas-snippet-beg)
(end yas-snippet-end))
(yas-expand-snippet
(buffer-substring-no-properties beg end) beg end
(quote ((yas-indent-line nil) (yas-wrap-around-region nil))))
(delete-trailing-whitespace beg (- end 1)))}
The code for the .yas-setup.el is:
(defun python-args-to-google-docstring (text &optional make-fields)
"Return a reST docstring format for the python arguments in yas-text."
(let* ((indent (concat "\n" (make-string (current-column) 32)))
(args (python-split-args text))
(nr 0)
(formatted-args
(mapconcat
(lambda (x)
(concat " " (nth 0 x)
(if make-fields (format " ${%d:arg%d}" (cl-incf nr) nr))
(if (nth 1 x) (concat " \(default " (nth 1 x) "\)"))))
args
indent)))
(unless (string= formatted-args "")
(concat
(mapconcat 'identity
(list "" "Args:" formatted-args)
indent)
"\n"))))
Note that python-split-args is provided by the standard snippets. I.e.:
https://github.com/AndreaCrotti/yasnippet-snippets/tree/master You do however get those by default when you install the package through package.el.
With everything setup properly, you should be able to write "defg" followed by Tab to expand the snippet (See the image for an example).
There is still an issue with using this inside nested indentation, e.g., within classes or as nested functions. In those cases the docstring is erroneously indented an extra time for some reason. I'll update this post if I manage to fix that.
The snippet should now work inside other scopes by forbidding yasnippet from auto-indenting the second expansion.
As lunaryorn mentioned that style is not popular and there aren't any packages.
However there is a package called sphinx-doc which will generate doc string in sphinx format(demo).
You can modify that package to generate strings as per your requirement.
Assuming you would like to use napoleon to render your docstrings into docs, the sphinx developers are working towards a way to add custom sections to class-level docstrings (see Issue #33).
Currently, in the Google Style Docstrings Example, the class ExamplePEP526Class example states
If the class has public attributes, they may be documented here in an
Attributessection and follow the same formatting as a function'sArgssection. Ifnapoleon_attr_annotationsis True, types can be specified in the class body usingPEP 526annotations.
PEP 526 added variable annotations to type hints. Hence, your code could now be written:
"""Sandbox module"""
class Toto:
""" This class is an example
Attributes:
class_attribute (str): (class attribute) The class attribute
instance_attribute (str): The instance attribute
"""
class_attribute: str = ""
def __init__(self):
self.instance_attribute: str = ""
For one thing, it seems you forgot to put the type hint str after class_attribute when defining it, so mypy (if using an external type checker) probably couldn't discover its type.
Ironically, the reverse situation would have worked: in napoleon version 3.4, if napoleon_attr_attributes is set to True, then
If an attribute is documented in the docstring without a type and has an annotation in the class body, that type is used.
Second, the pass at the end of your __init__ method is allowed, but unnecessary since you define instance_attribute there.
I mention Issue #33 because, personally, I would rather call the heading "Class Variables" as "Attributes" by itself doesn't distinguish between instance vs. class attributes/variables. For the time being, you may want to put your own notation in the attribute description like I have done.
For me, I either have fewer class attributes than instance attributes or none at all, so I only note if an attribute is a class attribute (otherwise, it is an instance attribute). That way, I don't have to write (instance attribute) next to all my instance attributes. Alternatively, you could try putting class in the parentheses with the type the same what that optional is listed:
class_attribute (str, class): The class attribute
I'm not sure if that will work or break. If it breaks, it would certainly be nice to have added to the docstring syntax in the future (I think this looks cleaner).
Lastly, you could document the class variable as an attribute docstring as defined in PEP 257 as well as this SO answer by putting a docstring directly underneath the assignment like so:
"""Sandbox module"""
class Toto:
class_attribute: str = ""
"""class_attribute (str): (class attribute) The class attribute"""
def __init__(self):
""" This class is an example
Attributes:
instance_attribute (str): The instance attribute
"""
self.instance_attribute: str = ""
Try this:
"""
Sandbox module
~~~~~~~~~~~~~~
"""
class Toto:
"""This class is an example
Attributes:
instance_attribute (str): The instance attribute #OK
"""
#: str: The class attribute #Unresolved reference
class_attribute = ""
def __init__(self):
self.instance_attribute = ""
pass
This works fine for me using sphinx.