Comments, Docstrings, and Type Hints in Python Code

The source code of a program should be readable to humans. Making it run correctly is only half of its purpose. Without a properly commenting code, it would be difficult for one, including the future you, to understand the rationale and intent behind the code. It would also make the code impossible to maintain. In Python, there are multiple ways to add descriptions to the code to make it more readable or make the intent more explicit. In the following, we will see how we should properly use comments, docstrings, and type hints to make our code easier to understand. After finishing this tutorial, you will know:

  • What is the proper way of using comments in Python
  • How string literal or docstring can replace comments in some cases
  • What are type hints in Python, and how they can help us understand the code better

Kick-start your project with my new book Python for Machine Learning, including step-by-step tutorials and the Python source code files for all examples.

Let’s get started.

Comments, Docstrings, and Type Hints in Python Code. Photo by Rhythm Goyal. Some rights reserved

Overview

This tutorial is in three parts, they are:

  • Adding comments to Python code
  • Using docstrings
  • Using type hints in Python code

Adding Comments to Python Code

Almost all programming languages have dedicated syntax for comments. Comments are to be ignored by compilers or interpreters, and hence they have no effect on the programming flow or logic. But with comments, it is easier to read the code.

In languages like C++, we can add “inline comments” with a leading double slash (//) or add comment blocks enclosed by /* and */. However, in Python, we only have the “inline” version, and they are introduced by the leading hash character (#).

It is quite easy to write comments to explain every line of code, but that is usually a waste. When people read the source code, comments often easily catch their attention, and hence putting too many comments would distract the reading. For example, the following is unnecessary and distracting:

Comments like these are merely repeating what the code does. Unless the code is obscure, these comments add no value to the code. The example below might be a marginal case in which the name “ppf” (percentage point function) is less well-known than the term “CDF” (cumulative distribution function):

Good comments should tell why we are doing something. Let’s look at the following example:

The function above is implementing the AdaDelta algorithm. In the first line, when we assign something to the variable solution, we do not write comments like “a random interpolation between bounds[:,0] and bounds[:,1]” because that is just repeating the code. We say the intent of this line is to “generate an initial point.” Similarly, for the other comments in the function, we mark one of the for-loops as the gradient descent algorithm rather than just saying iterate for certain times.

One important issue we want to remember when writing the comment or modifying code is to make sure the comment accurately describes the code. If they contradict, it would be confusing to the readers. So should we not have put the comment on the first line of the above example to “set initial solution to the lowerbound” while the code obviously randomizes the initial solution, or vice versa. If this is what you intended to do, you should update the comment and the code at the same time.

An exception would be the “to-do” comments. From time to time, when we have an idea on how to improve the code but have not yet changed it, we may put to-do comments on the code. We can also use it to mark incomplete implementations. For example,

This is a common practice, and many IDE will highlight the comment block differently when the keyword TODO is found. However, it’s supposed to be temporary, and we should not abuse it as an issue-tracking system.

In summary, some common “best practices” on commenting code are listed as follows:

  • Comments should not restate the code but explain it
  • Comments should not cause confusion but eliminate it
  • Put comments on code that is not trivial to understand; for example, state the unidiomatic use of syntax, name the algorithm being used, or explain the intent or assumptions
  • Comments should be concise and simple
  • Keep a consistent style and use of language in commenting
  • Always prefer to have a better-written code that needs no additional comments

Using Docstrings

In C++, we may write a large block of comments such as in the following:

But in Python, we do not have an equivalent to the delimiters /* and */, but we can write multi-line comments using the following instead:

This works because Python supports declaring a string literal spanning across multiple lines if it is delimited with triple quotation marks ("""). And a string literal in the code is merely a string declared with no impact. Therefore it is functionally no different than the comments.

One reason we want to use string literals is to comment out a large block of code. For example,

The above is a sample code that we may develop by experimenting with a machine learning problem. While we generated a dataset randomly at the beginning (the call to make_classification() above), we may want to switch to a different dataset and repeat the same process at a later time (e.g., the pickle part above). Rather than removing the block of code, we may simply comment on those lines so that we can store the code later. It is not in good shape for the finalized code but convenient while developing our solution.

The string literal in Python as a comment has a special purpose if it is in the first line under a function. The string literal, in that case, is called the “docstring” of the function. For example,

We can see the first line under the function is a literal string, and it serves the same purpose as a comment. It makes the code more readable, but at the same time, we can retrieve it from the code:

Because of the special status of the docstring, there are several conventions on how to write a proper one.

In C++, we may use Doxygen to generate code documentation from comments, and similarly, we have Javadoc for Java code. The closest match in Python would be the tool “autodoc” from Sphinx or pdoc. Both will try to parse the docstring to generate documentation automatically.

There is no standard way of making docstrings, but generally, we expect they will explain the purpose of a function (or a class or module) as well as the arguments and the return values. One common style is like the one above, which is advocated by Google. A different style is from NumPy:

Tools such as autodoc can parse these docstrings and generate the API documentation. But even if it is not the purpose, having a docstring describing the nature of the function, the data types of the function arguments and return values can surely make your code easier to read. This is particularly true since Python, unlike C++ or Java, is a duck-typing language in which variables and function arguments are not declared with a particular type. We can make use of docstrings to spell out the assumptions of the data type so people can more easily follow or use your function.

Want to Get Started With Python for Machine Learning?

Take my free 7-day email crash course now (with sample code).

Click to sign-up and also get a free PDF Ebook version of the course.

Using Type Hints in Python Code

Since Python 3.5, type hint syntax is allowed. As the name implies, its purpose is to hint at the type and nothing else. Hence even if it looks to bring Python closer to Java, it does not mean to restrict the data to be stored in a variable. The example above can be rewritten with a type hint:

In a function, the arguments can be followed by a : type syntax to spell out the intended types. The return value of a function is identified by the -> type syntax before the colon. In fact, a type hint can be declared for variables too, e.g.,

The benefit of a type hint is twofold: We can use it to eliminate some comments if we need to describe explicitly the data type being used. We can also help static analyzers understand our code better so they can help identify potential issues in the code.

Sometimes the type can be complex, and therefore Python provided the typing module in its standard library to help clean up the syntax. For example, we can use Union[int,float] to mean int type or float type, List[str] to mean a list that every element is a string, and use Any to mean anything. Like as follows:

However, it is important to remember that type hints are hints only. It does not impose any restrictions on the code. Hence the following is confusing to the reader but perfectly fine:

Using type hints may improve the readability of the code. However, the most important benefit of type hints is to allow a static analyzer such as mypy to tell us whether our code has any potential bugs. If you process the above lines of code with mypy, we will see the following error:

The use of static analyzers will be covered in another post.

To illustrate the use of comments, docstrings, and type hints, below is an example to define a generator function that samples a pandas DataFrame on fixed-width windows. It is useful for training an LSTM network, in which a few consecutive time steps should be provided. In the function below, we start from a random row on the DataFrame and clip a few rows following it. As long as we can successfully get one full window, we take it as a sample. Once we’ve collected enough samples to make a batch, the batch is dispatched.

You should see that it is clearer if we can provide type hints on the function arguments, so we know, for example, that data is supposed to be a pandas DataFrame. But we describe further that it is expected to carry a datetime index in the docstring. We describe the algorithm on how to exact a window of rows from the input data as well as the intention of the “if” block in the inner while-loop using comments. In this way, the code is much easier to understand and much easier to maintain or modify for other use.

Further reading

This section provides more resources on the topic if you are looking to go deeper.

Articles

Software

Summary

In this tutorial, you’ve seen how we should use the comments, docstrings, and type hints in Python. Specifically, you now know:

  • How to write a good, useful comment
  • The conventions in explaining a function using docstrings
  • How to use type hints to address the readability weakness of duck-typing in Python

Get a Handle on Python for Machine Learning!

Python For Machine Learning

Be More Confident to Code in Python

...from learning the practical Python tricks

Discover how in my new Ebook:
Python for Machine Learning

It provides self-study tutorials with hundreds of working code to equip you with skills including:
debugging, profiling, duck typing, decorators, deployment, and much more...

Showing You the Python Toolbox at a High Level for
Your Projects


See What's Inside

One Response to Comments, Docstrings, and Type Hints in Python Code

  1. Avatar
    Karl Bergerson February 24, 2022 at 6:09 pm #

    Please have a native English speaker review / edit the commentary.

Leave a Reply