15

I have seen several standards for writing comments about the kind of data a function expects and returns in Python. Is there a consensus on which one is best-practice?

Is the new functionality in http://www.python.org/dev/peps/pep-3107/ something I should start using for this?

Joakim Lundborg
  • 10,920
  • 6
  • 32
  • 39

3 Answers3

22

Function annotations are not for a specific use, they can be used for anything.

Tools can be written to extract information from the annotations and do anything you want, including checking types or generating documentation. But python itself does not do anything with the information. You could use to a completely different purpose, i.e. to provide a function that will be called on the parameter or to declare a string of possible return values.

Annotations can be any object:

def somefunc(param1: "string annotation", 
             param2: 151631,  
             param3: any_object): -> "some information here":

and you can retrieve the objects using:

print (somefunc.func_annotations)
{'param1': "string annotation", 
 'param2': 151631,  
 'param3': <object any_object>,
 'return': "some information here"}

Use case suggestions provided by the PEP:

  • Providing typing information
    • Type checking
    • Let IDEs show what types a function expects and returns
    • Function overloading / generic functions
    • Foreign-language bridges
    • Adaptation
    • Predicate logic functions
    • Database query mapping
    • RPC parameter marshaling
  • Other information
    • Documentation for parameters and return values

Since function annotation syntax is too new, it is really not used for any production tools.

I suggest using other methods to document that. I use epydoc to generate my documentation, and it can read parameter typing information from docstrings:

def x_intercept(m, b):
    """
    Return the x intercept of the line M{y=m*x+b}.  The X{x intercept}
    of a line is the point at which it crosses the x axis (M{y=0}).

    This function can be used in conjuction with L{z_transform} to
    find an arbitrary function's zeros.

    @type  m: number
    @param m: The slope of the line.
    @type  b: number
    @param b: The y intercept of the line.  The X{y intercept} of a
              line is the point at which it crosses the y axis (M{x=0}).
    @rtype:   number
    @return:  the x intercept of the line M{y=m*x+b}.
    """
    return -b/m

This example is from epydoc's website. It can generate documentation in a variety of formats, and can generate good graphs from your classes and call profiles.

nosklo
  • 217,122
  • 57
  • 293
  • 297
  • Can you elaborate at which version of Python this syntax was added? – pi. Jan 28 '09 at 10:57
  • A reference implementation has been checked into the p3yk branch as revision 53170: http://svn.python.org/view?rev=53170&view=rev – S.Lott Jan 28 '09 at 11:23
11

If you use epydoc to produce API documentation, you have three choices.

  • Epytext.

  • ReStructuredText, RST.

  • JavaDoc notation, which looks a bit like epytext.

I recommend RST because it works well with sphinx for generating overall documentation suite that includes API references. RST markup is defined here. The various epydoc fields you can specify are defined here.

Example.

def someFunction( arg1, arg2 ):
    """Returns the average of *two* (and only two) arguments.

    :param arg1: a numeric value
    :type arg1: **any** numeric type

    :param arg2: another numeric value
    :type arg2: **any** numeric type

    :return: mid-point (or arithmetic mean) between two values 
    :rtype: numeric type compatible with the args.
    """
    return (arg1+arg2)/2
S.Lott
  • 384,516
  • 81
  • 508
  • 779
7

Python 3.5 official typing

https://docs.python.org/3/library/typing.html

This update makes types an actual part of the language.

Example:

#!/usr/bin/env python3

from typing import List

def f(x: int, ys: List[float]) -> str:
    return "abc"

# Good.
f(1, [2.0, 3.0])

# Bad.
f("abc", {}) # line 12

x = 1
x = "a" # line 15

y = [] # type: List[int]
y.append("a") # line 18

This code runs normally: Python 3.5 does not enforce typing by default.

But it can however be used by static linters to diagnoze problems, e.g.:

sudo pip3 install mypy
mypy a.py

gives:

a.py:12: error: Argument 1 to "f" has incompatible type "str"; expected "int"
a.py:12: error: Argument 2 to "f" has incompatible type Dict[<nothing>, <nothing>]; expected List[float]
a.py:15: error: Incompatible types in assignment (expression has type "str", variable has type "int")
a.py:18: error: Argument 1 to "append" of "list" has incompatible type "str"; expected "int"

Existing static analyzers like Pycharm's can already parse Sphinx documentation types, but this language update gives an official canonical way that will likely prevail.

Sphinx 1.8.2 does not seem to support it yet, but it is only a matter of time: Python 3: Sphinx doesn't show type hints correctly

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985