| Nov | DEC | Jan |
| 01 | ||
| 2020 | 2021 | 2022 |
COLLECTED BY
Collection: Save Page Now
#) and should be brief statements no longer than a few sentences. Here’s a simple example:
def hello_world():
# A simple comment preceding a simple print statement
print("Hello World")
According to PEP 8, comments should have a maximum length of 72 characters. This is true even if your project changes the max line length to be greater than the recommended 80 characters. If a comment is going to be greater than the comment char limit, using multiple lines for the comment is appropriate:
def hello_long_world():
# A very long statement that just goes on and on and on and on and
# never ends until after it's reached the 80 char limit
print("Hellooooooooooooooooooooooooooooooooooooooooooooooooooooooo World")
Commenting your code serves multiple purposes, including:
Planning and Reviewing: When you are developing new portions of your code, it may be appropriate to first use comments as a way of planning or outlining that section of code. Remember to remove these comments once the actual coding has been implemented and reviewed/tested:
# First step
# Second step
# Third step
Code Description: Comments can be used to explain the intent of specific sections of code:
# Attempt a connection based on previous settings. If unsuccessful,
# prompt user for new settings.
Algorithmic Description: When algorithms are used, especially complicated ones, it can be useful to explain how the algorithm works or how it’s implemented within your code. It may also be appropriate to describe why a specific algorithm was selected over another.
# Using quick sort for performance gains
Tagging: The use of tagging can be used to label specific sections of code where known issues or areas of improvement are located. Some examples are: BUG, FIXME, and TODO.
# TODO: Add condition for when val is None
Comments to your code should be kept brief and focused. Avoid using long comments when possible. Additionally, you should use the following four essential rules as suggested by Jeff Atwood:
Keep comments as close to the code being described as possible. Comments that aren’t near their describing code are frustrating to the reader and easily missed when updates are made.
Don’t use complex formatting (such as tables or ASCII figures). Complex formatting leads to distracting content and can be difficult to maintain over time.
Don’t include redundant information. Assume the reader of the code has a basic understanding of programming principles and language syntax.
Design your code to comment itself. The easiest way to understand code is by reading it. When you design your code using clear, easy-to-understand concepts, the reader will be able to quickly conceptualize your intent.
Remember that comments are designed for the reader, including yourself, to help guide them in understanding the purpose and design of the software.
def hello_name(name: str) -> str:
return(f"Hello {name}")
From examining the type hinting, you can immediately tell that the function expects the input name to be of a type str, or string. You can also tell that the expected output of the function will be of a type str, or string, as well. While type hinting helps reduce comments, take into consideration that doing so may also make extra work when you are creating or updating your project documentation.
You can learn more about type hinting and type checking from this video created by Dan Bader.
Remove ads
help() that prints out the objects docstring to the console. Here’s a quick example:
>>>>>> help(str)
Help on class str in module builtins:
class str(object)
| str(object='') -> str
| str(bytes_or_buffer[, encoding[, errors]]) -> str
|
| Create a new string object from the given object. If encoding or
| errors are specified, then the object must expose a data buffer
| that will be decoded using the given encoding and error handler.
| Otherwise, returns the result of object.__str__() (if defined)
| or repr(object).
| encoding defaults to sys.getdefaultencoding().
| errors defaults to 'strict'.
# Truncated for readability
How is this output generated? Since everything in Python is an object, you can examine the directory of the object using the dir() command. Let’s do that and see what find:
>>>>>> dir(str)
['__add__', ..., '__doc__', ..., 'zfill'] # Truncated for readability
Within that directory output, there’s an interesting property, __doc__. If you examine that property, you’ll discover this:
>>>>>> print(str.__doc__)
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or
errors are specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
Voilà! You’ve found where docstrings are stored within the object. This means that you can directly manipulate that property. However, there are restrictions for builtins:
>>>>>> str.__doc__ = "I'm a little string doc! Short and stout; here is my input and print me for my out"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
Any other custom object can be manipulated:
def say_hello(name):
print(f"Hello {name}, is it me you're looking for?")
say_hello.__doc__ = "A simple function that says hello... Richie style"
>>>>>> help(say_hello)
Help on function say_hello in module __main__:
say_hello(name)
A simple function that says hello... Richie style
Python has one more feature that simplifies docstring creation. Instead of directly manipulating the __doc__ property, the strategic placement of the string literal directly below the object will automatically set the __doc__ value. Here’s what happens with the same example as above:
def say_hello(name):
"""A simple function that says hello... Richie style"""
print(f"Hello {name}, is it me you're looking for?")
>>>>>> help(say_hello)
Help on function say_hello in module __main__:
say_hello(name)
A simple function that says hello... Richie style
There you go! Now you understand the background of docstrings. Now it’s time to learn about the different types of docstrings and what information they should contain.
""") string format. This should be done whether the docstring is multi-lined or not. At a bare minimum, a docstring should be a quick summary of whatever is it you’re describing and should be contained within a single line:
"""This is a quick summary line used as a description of the object."""
Multi-lined docstrings are used to further elaborate on the object beyond the summary. All multi-lined docstrings have the following parts:
●A one-line summary line
●A blank line proceeding the summary
●Any further elaboration for the docstring
●Another blank line
"""This is the summary line
This is the further elaboration of the docstring. Within this section,
you can elaborate further on details as appropriate for the situation.
Notice that the summary and the elaboration is separated by a blank new
line.
"""
# Notice the blank line above. Code should continue on this line.
All docstrings should have the same max character length as comments (72 characters). Docstrings can be further broken up into three major categories:
●Class Docstrings: Class and class methods
●Package and Module Docstrings: Package, modules, and functions
●Script Docstrings: Script and functions
class SimpleClass:
"""Class docstrings go here."""
def say_hello(self, name: str):
"""Class method docstrings go here."""
print(f'Hello {name}')
Class docstrings should contain the following information:
●A brief summary of its purpose and behavior
●Any public methods, along with a brief description
●Any class properties (attributes)
●Anything related to the interface for subclassers, if the class is intended to be subclassed
The class constructor parameters should be documented within the __init__ class method docstring. Individual methods should be documented using their individual docstrings. Class method docstrings should contain the following:
●A brief description of what the method is and what it’s used for
●Any arguments (both required and optional) that are passed including keyword arguments
●Label any arguments that are considered optional or have a default value
●Any side effects that occur when executing the method
●Any exceptions that are raised
●Any restrictions on when the method can be called
Let’s take a simple example of a data class that represents an Animal. This class will contain a few class properties, instance properties, a __init__, and a single instance method:
class Animal:
"""
A class used to represent an Animal
...
Attributes
----------
says_str : str
a formatted string to print out what the animal says
name : str
the name of the animal
sound : str
the sound that the animal makes
num_legs : int
the number of legs the animal has (default 4)
Methods
-------
says(sound=None)
Prints the animals name and what sound it makes
"""
says_str = "A{name} says {sound}"
def __init__(self, name, sound, num_legs=4):
"""
Parameters
----------
name : str
The name of the animal
sound : str
The sound the animal makes
num_legs : int, optional
The number of legs the animal (default is 4)
"""
self.name = name
self.sound = sound
self.num_legs = num_legs
def says(self, sound=None):
"""Prints what the animals name is and what sound it makes.
If the argument `sound` isn't passed in, the default Animal
sound is used.
Parameters
----------
sound : str, optional
The sound the animal makes (default is None)
Raises
------
NotImplementedError
If no sound is set for the animal or passed in as a
parameter.
"""
if self.sound is None and sound is None:
raise NotImplementedError("Silent Animals are not supported!")
out_sound = self.sound if sound is None else sound
print(self.says_str.format(name=self.name, sound=out_sound))
__init__.py file. This docstring should list the modules and sub-packages that are exported by the package.
Module docstrings are similar to class docstrings. Instead of classes and class methods being documented, it’s now the module and any functions found within. Module docstrings are placed at the top of the file even before any imports. Module docstrings should include the following:
●A brief description of the module and its purpose
●A list of any classes, exception, functions, and any other objects exported by the module
The docstring for a module function should include the same items as a class method:
●A brief description of what the function is and what it’s used for
●Any arguments (both required and optional) that are passed including keyword arguments
●Label any arguments that are considered optional
●Any side effects that occur when executing the function
●Any exceptions that are raised
●Any restrictions on when the function can be called
-h option.
If you use argparse, then you can omit parameter-specific documentation, assuming it’s correctly been documented within the help parameter of the argparser.parser.add_argument function. It is recommended to use the __doc__ for the description parameter within argparse.ArgumentParser’s constructor. Check out our tutorial on Command-Line Parsing Libraries for more details on how to use argparse and other common command line parsers.
Finally, any custom or third-party imports should be listed within the docstrings to allow users to know which packages may be required for running the script. Here’s an example of a script that is used to simply print out the column headers of a spreadsheet:
"""Spreadsheet Column Printer
This script allows the user to print to the console all columns in the
spreadsheet. It is assumed that the first row of the spreadsheet is the
location of the columns.
This tool accepts comma separated value files (.csv) as well as excel
(.xls, .xlsx) files.
This script requires that `pandas` be installed within the Python
environment you are running this script in.
This file can also be imported as a module and contains the following
functions:
* get_spreadsheet_cols - returns the column headers of the file
* main - the main function of the script
"""
import argparse
import pandas as pd
def get_spreadsheet_cols(file_loc, print_cols=False):
"""Gets and prints the spreadsheet's header columns
Parameters
----------
file_loc : str
The file location of the spreadsheet
print_cols : bool, optional
A flag used to print the columns to the console (default is
False)
Returns
-------
list
a list of strings used that are the header columns
"""
file_data = pd.read_excel(file_loc)
col_headers = list(file_data.columns.values)
if print_cols:
print("\n".join(col_headers))
return col_headers
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'input_file',
type=str,
help="The spreadsheet file to pring the columns of"
)
args = parser.parse_args()
get_spreadsheet_cols(args.input_file, print_cols=True)
if __name__ == "__main__":
main()
Remove ads
Arguments, Returns, and Attributes. There are specific docstrings formats that can be used to help docstring parsers and users have a familiar and known format. The formatting used within the examples in this tutorial are NumPy/SciPy-style docstrings. Some of the most common formats are the following:
| Formatting Type | Description | Supported by Sphynx | Formal Specification |
|---|---|---|---|
| Google docstrings | Google’s recommended form of documentation | Yes | No |
| reStructured Text | Official Python documentation standard; Not beginner friendly but feature rich | Yes | Yes |
| NumPy/SciPy docstrings | NumPy’s combination of reStructured and Google Docstrings | Yes | Yes |
| Epytext | A Python adaptation of Epydoc; Great for Java developers | Not officially | Yes |
"""Gets and prints the spreadsheet's header columns
Args:
file_loc (str): The file location of the spreadsheet
print_cols (bool): A flag used to print the columns to the console
(default is False)
Returns:
list: a list of strings representing the header columns
"""
"""Gets and prints the spreadsheet's header columns
:param file_loc: The file location of the spreadsheet
:type file_loc: str
:param print_cols: A flag used to print the columns to the console
(default is False)
:type print_cols: bool
:returns: a list of strings representing the header columns
:rtype: list
"""
"""Gets and prints the spreadsheet's header columns
Parameters
----------
file_loc : str
The file location of the spreadsheet
print_cols : bool, optional
A flag used to print the columns to the console (default is False)
Returns
-------
list
a list of strings representing the header columns
"""
"""Gets and prints the spreadsheet's header columns
@type file_loc: str
@param file_loc: The file location of the spreadsheet
@type print_cols: bool
@param print_cols: A flag used to print the columns to the console
(default is False)
@rtype: list
@returns: a list of strings representing the header columns
"""
project_root/
│
├── project/ # Project source code
├── docs/
├── README
├── HOW_TO_CONTRIBUTE
├── CODE_OF_CONDUCT
├── examples.py
Projects can be generally subdivided into three major types: Private, Shared, and Public/Open Source.
examples.py: A Python script file that gives simple examples of how to use the project.
Remember, even though private projects are intended for you personally, you are also considered a user. Think about anything that may be confusing to you down the road and make sure to capture those in either comments, docstrings, or the readme.
Remove ads
examples.py: A Python script file that gives simple examples of how to use the projects.
●How to Contribute: This should include how new contributors to the project can start contributing.
docs Folder
| Most Useful When We’re Studying | Most Useful When We’re Coding | |
|---|---|---|
| Practical Step | Tutorials | How-To Guides |
| Theoretical Knowledge | Explanation | Reference |
| Tool | Description |
|---|---|
| Sphinx | A collection of tools to auto-generate documentation in multiple formats |
| Epydoc | A tool for generating API documentation for Python modules based on their docstrings |
| Read The Docs | Automatic building, versioning, and hosting of your docs for you |
| Doxygen | A tool for generating documentation that supports Python as well as multiple other languages |
| MkDocs | A static site generator to help build project documentation using the Markdown language |
| pycco | A “quick and dirty” documentation generator that displays code and documentation side by side. Check out our tutorial on how to use it for more info. |
About James Mertz

James is a passionate Python developer at NASA's Jet Propulsion Lab who also writes on the side for Real Python.
» More about James
Dan

🔒 No spam. Unsubscribe any time.
All Tutorial Topics advanced api basics best-practices community databases data-science devops django docker flask front-end gamedev gui intermediate machine-learning projects python testing tools web-dev web-scraping Table of Contents ●Why Documenting Your Code Is So Important ●Commenting vs Documenting Code ●Basics of Commenting Code ●Commenting Code via Type Hinting (Python 3.5+) ●Documenting Your Python Code Base Using Docstrings ●Docstrings Background ●Docstring Types ●Docstring Formats ●Documenting Your Python Projects ●Private Projects ●Shared Projects ●Public and Open Source Projects ●Documentation Tools and Resources ●Where Do I Start? Tweet Share Email Recommended Video Course Documenting Python Code: A Complete Guide Remove ads © 2012–2021 Real Python ⋅ Newsletter ⋅ Podcast ⋅ YouTube ⋅ Twitter ⋅ Facebook ⋅ Instagram ⋅ Python Tutorials ⋅ Search ⋅ Privacy Policy ⋅ Energy Policy ⋅ Advertise ⋅ Contact ❤️ Happy Pythoning!