Docstrings

Contents

Docstrings#

You may recall our previous discussion about writing readable code and the importance of documentation. Functions provide us with a new means of documenting our code via docstrings. These are essentially block comments that we add to function definitions to explain exactly what that function does, the arguments expected from the user etc. To use a concrete example, let’s say I’ve written a function to calculate the kinetic energy of a particle as:

\[T = \frac{1}{2}mv^{2}.\]
def kinetic_energy(m, v):
    return (1 / 2) * m * v ** 2

Even though this is simple enough that a docstring may not seem strictly necessary, it is good practice to write docstrings for all functions. To add a docstring, we use triple quotes """:

def kinetic_energy(m, v):
    """
    Calculate the kinetic energy as 1/2mv^2.

    Args:
        m (float): The mass of the particle.
        v (float): The velocity of the particle.

    Returns:
        (float): The kinetic energy of the particle.
    """
    return (1 / 2) * m * v ** 2

Our docstring can be split into several sections. At the top we have a brief description of what the function does: a general summary.

Next we have an Args section, which details each of the arguments we expected to be passed to the function and what type each one should be.

Finally we have a Returns section, which tells us what the function should return and the type of this result.

The exact format of this example docstring follows the Google style, but there are various other standards for formatting docstrings too.

If you are working with a function that has been properly documented, you can access the docstring in a few different ways. Firstly, and most obviously, you can just look at the source code itself. We can do this easily here as we have literally just defined kinetic_energy ourselves, but if someone else had written it, this would not be as quick and easy an option.

Option two is to access the __doc__ attribute:

print(kinetic_energy.__doc__)
    Calculate the kinetic energy as 1/2mv^2.

    Args:
        m (float): The mass of the particle.
        v (float): The velocity of the particle.

    Returns:
        (float): The kinetic energy of the particle.
    

Python will define a __doc__ attribute for every function that has been properly documented, we can print this to access the docstring.

Option three is only available in Jupyter notebooks, but is generally the quickest and easiest if available:

kinetic_energy?

We have just demonstrated how to access the docstring associated with our own kinetic_energy function, but the same methods work for any function, even built-in functions:

print(len.__doc__)
Return the number of items in a container.
len?

For all the same reasons as we previously discussed for comments and Markdown cells, it is good practice to make heavy use of docstrings. In fact, you should really write a docstring for every function you write, it takes \(2\) minutes and could save you a lot of trouble down the line.

Exercise#

1. Define your own functions (with docstrings) to calculate the following quantities:

a) The De Broglie wavelength:

\[\lambda = \frac{h}{p},\]

where \(h\) is Planck’s constant and \(p\) is the momentum. You can access \(h\) via scipy.constants.h, or alternatively you may pass it directly as an argument.

Test your function for \(p = 1.01 \times 10^{-31}\,\)kgms\(^{-1}\).

b) The change in the Gibbs free energy:

\[\Delta G = -RT\ln K,\]

where \(R\) is the gas constant, \(T\) is the temperature and \(K\) is the equilibrium constant.

Test your function for \(T = 500\,\)K and \(K = 1.15\).

c) The mean activity according to the Debye-Huckel limiting law:

\[\gamma_{\pm} = \exp\left[-|z_{+}z_{-}|A\sqrt{I}\right],\]

where \(z_{+}\) and \(z_{-}\) are the charges on the cations and anions respectively, \(I\) is the ionic strength and \(A\) is a constant that depends upon the solvent and the temperature.

Test your function for \(z_{+} = 1\), \(z_{-} = 2\), \(A = 1.179\,\)M\(^{\frac{1}{2}}\) and \(I = 0.018\,\)M.

Answers:

\[\lambda = 6.56 \times 10^{-3}\,\mathrm{m}\]
\[\Delta G = -5.81 \times 10^{-1}\,\mathrm{kJmol}^{-1}\]
\[\gamma_{\pm} = 0.729 \]

2.

a) The thermal De Broglie wavelength describes the average De Broglie wavelength of particles in an ideal gas at a given temperature:

\[\Lambda = \frac{h}{\sqrt{2\pi mk_{\mathrm{B}}T}},\]

where \(h\) is Planck’s constant, \(m\) is the mass of each particle, \(k_{B}\) is Boltzmann’s constant and \(T\) is the temperature.

Write a function to calculate \(\Lambda\). You can access \(k_{B}\) via scipy.constants.k.

b) The entropy of an ideal gas can be calculated with the Sackur-Tetrode equation:

\[\frac{S}{k_{\mathrm{B}}N} = \ln\left(\frac{V}{N\Lambda^{3}}\right) + \frac{5}{2},\]

where \(S\) is the entropy, \(N\) is the number of particles, \(V\) is the volume, \(k_{\mathrm{B}}\) is Boltzmann’s constant and \(\Lambda\) is the thermal wavelength mentioned prior.

Write a function to calculate the entropy of an ideal gas with the Sackur-Tetrode equation.

c) Using your two functions, calculate the entropy of an ideal gas with \(m = 6.63 \times 10^{-26}\,\)kg, \(T = 500\,\)K, \(N = 1.92 \times 10^{23}\) and \(V = 5.00 \times 10^{-3}\,\)m\(^{-3}\).

Answers:

\[S = 50.2\,\mathrm{JK}^{-1}\]