Using Python's builtin help system
By John Lekberg on January 29, 2020.
Python has a builtin help system which you can activate using the help function:
help()
Welcome to Python 3.7's help utility!
If this is your first time using Python, you should
definitely check out the tutorial on the Internet at
https://docs.python.org/3.7/tutorial/.
Enter the name of any module, keyword, or topic to get help
on writing Python programs and using Python modules. To
quit this help utility and return to the interpreter, just
type "quit".
...
In this week's Python blog post, you will learn
 how to use the help system to learn about unfamiliar code, and
 how to make your own code work with the help system.
When do I use the help system?
Python has great online documentation which covers the same topics as the help system, so when do I use the help system instead of the online documentation?

When I want to learn about something that is difficult to Google, like
3j
help(3j)
Help on complex object: class complex(object)  complex(real=0, imag=0)   Create a complex number from a real part and an  optional imaginary part.   ...
or
**
help("**")
The power operator ****************** The power operator binds more tightly than unary operators on its left; it binds less tightly than unary operators on its right. ...

When I want to learn about the results of a function without having to delve into lots of API documentation:
import urllib.request result = urllib.request.urlopen("http://example.com") help(result)
Help on HTTPResponse in module http.client object: class HTTPResponse(io.BufferedIOBase)  HTTPResponse(sock, debuglevel=0, method=None, url=None)   ...   Methods defined here:   ...   getcode(self)  Return the HTTP status code that was sent with the  response, or None if the URL is not an HTTP URL.   getheader(self, name, default=None)  Returns the value of the header matching *name*.  ...   ...
Using the help system on unfamiliar code
Here is a short story about using the help system to understand my friend's code.
I'm working on a programming challenge with my friend Mia 👩🏻 . The challenge is to design a function that returns the sum of the first n Fibonacci numbers. I'm having trouble with this, so I ask Mia how she solved the problem. She shows me her code:
import itertools def fibonacci(): a, b = 1, 1 while True: yield a a, b = b, a + b def sum_fib(n): return sum(itertools.islice(fibonacci(), n)) sum_fib(100)
927372692193078999175
I tell her that there are 3 things I don't understand:
 What does yield do?
 What does
a, b = b, a + b
mean?  What does the itertools.islice function do?
Mia laughs and tells me to figure it out for myself, so I boot up the Python interpreter and start the interactive help system:
$ python3 >>> help()
Welcome to Python 3.7's help utility!
If this is your first time using Python, you should
definitely check out the tutorial on the Internet at
https://docs.python.org/3.7/tutorial/.
...
help>
What does yield
do?
help> yield
The "yield" statement
*********************
...
Yield expressions and statements are only used when defining
a *generator* function, and are only used in the body of the
generator function. Using yield in a function definition is
sufficient to cause that definition to create a generator
function instead of a normal function.
...
(Yield expressions define generator functions.)
What does a, b = b, a + b
do?
Searching =
doesn't help:
help> =
No Python documentation found for '='.
I check which topics the help system covers:
help> topics
Here is a list of available topics. Enter any topic name to
get more help.
ASSERTION DELETION LOOPING
ASSIGNMENT DICTIONARIES MAPPINGMETHODS
ATTRIBUTEMETHODS DICTIONARYLITERALS MAPPINGS
...
I read more about assignment:
help> ASSIGNMENT
Assignment statements
*********************
...
An assignment statement evaluates the expression list
(remember that this can be a single expression or a
commaseparated list, the latter yielding a tuple) and
assigns the single resulting object to each of the target
lists, from left to right.
...
The object must be an iterable with the same number of items
as there are targets in the target list, and the items are
assigned, from left to right, to the corresponding targets
...
I learn that multiple assignment
a, b = b, a + b
is just like
x = (b, a + b)
a = x[0]
b = x[1]
(This is an easy way to swap names: x, y = y, x
.)
What does itertools.islice
do?
help> itertools.islice
Help on class islice in itertools:
itertools.islice = class islice(builtins.object)
 islice(iterable, stop) > islice object
 islice(iterable, start, stop[, step]) > islice object

 ...

 Works like a slice() on a list but returns an iterator.

 ...
For Mia's code, itertools.islice
takes the first n elements
generated by the fibonacci()
generator function.
I understand how Mia's code works now, so I explain it back to her. She tells me "good job" 🤷🏻♀️ and returns to her computer, solving the next programming challenge.
Making my own code available to the help system
Here is a short story about making my code work with the help system, in order to share my code with Mia 👩🏻 .
I wrote a function that creates a random binary tree and I want to share this with Mia. She wrote some algorithms that process binary trees and she wants to test them out on randomly generated trees instead of handwritten cases.
Here's my code:
from collections import namedtuple
import random
# Represents a node in a binary tree.
#
# None is used to represent absence of a branch, so a
# leaf node looks like Tree(x, None, None).
Tree = namedtuple("Tree", ["value", "left", "right"])
def random_tree(max_depth=1):
# Generate a random binary tree of depth at most
# max_depth.
#
# Each node has a value between 10 and 99. Each node
# (excluding nodes at the maximum depth) has an 80%
# chance of having a left child and an 80% chance of
# having a right child.
if max_depth == 0:
return
value = random.randint(10, 99)
left = right = None
if random.random() < 0.8:
left = random_tree(max_depth1)
if random.random() < 0.8:
right = random_tree(max_depth1)
return Tree(value, left, right)
The problem is that my comments don't show up when I ask the help system about
Tree
and random_tree
:
help(Tree)
Help on class Tree in module __main__:
class Tree(builtins.tuple)
 Tree(value, left, right)

 Tree(value, left, right)

 Method resolution order:
 Tree
 builtins.tuple
 ...
help(random_tree)
Help on function random_tree in module __main__:
random_tree(max_depth=1)
I want Mia to be able to use the help system to learn about the code I wrote,
so I turn the comments into docstrings (PEP 257).
Docstrings are strings that are attached to objects with the
__doc__
attribute.
Unlike comments, docstrings aren't thrown away by the Python Interpreter; they
are kept around and used by the help system.
I add a docstring to random_tree
as the first statement in the function:
def random_tree(max_depth=1):
"""Generate a random binary tree of depth at most
max_depth.
Each node has a value between 10 and 99. Each node
(excluding nodes at the maximum depth) has an 80% chance
of having a left child and an 80% chance of having a
right child.
"""
if max_depth == 0:
return
value = random.randint(10, 99)
left = right = None
if random.random() < 0.8:
left = random_tree(max_depth1)
if random.random() < 0.8:
right = random_tree(max_depth1)
return Tree(value, left, right)
(PEP 257 recommends using triple double quotes """
for docstrings.)
Now the help system includes my comments for random_tree
:
help(random_tree)
Help on function random_tree in module __main__:
random_tree(max_depth=1)
Generate a random binary tree of depth at most
max_depth.
Each node has a value between 10 and 99. Each node
(excluding nodes at the maximum depth) has an 80% chance
of having a left child and an 80% chance of having a
right child.
I add a docstring to Tree
by directly assigning __doc__
:
Tree = namedtuple("Tree", ["value", "left", "right"])
Tree.__doc__ = """Represents a node in a binary tree.
None is used to represent absence of a branch, so a
leaf node looks like Tree(x, None, None).
"""
Now the help system includes my comments for Tree
:
help(Tree)
Help on class Tree in module __main__:
class Tree(builtins.tuple)
 Tree(value, left, right)

 Represents a node in a binary tree.

 None is used to represent absence of a branch, so a
 leaf node looks like Tree(x, None, None).

 Method resolution order:
 ...
I share my code with Mia and she's able to figure out how it works and how to use it without needing to ask me. I tell Mia "good job" 🤷🏼♂️ and get back to solving the next programming challenge.
In conclusion...
Python has a builtin help system that can help you understand other people's code, as well as allow you to document your code for other people. It covers the same content as Python's online documentation but can be more useful when you want to learn about something that's hard to Google or when you want to learn about the results of a function without needing to pore over API documentation.
Python's docstring allow any kind of plain text comments to be written, but Python has special support for the reStructuredText format. My challenge to you is:
Read through PEP 287, "reStructuredText Docstring Format", to learn about using reStructuredText in docstrings. Then, document a Python function using reStructuredText. (Pick a function from the standard library or use the
random_tree
function that I shared with Mia.)
If you enjoyed this week's post, share it with your friends and stay tuned for next week's post. See you then!