Modules and Packages

Authors

Andrew Valentine

Louis Moresi

NoteSummary

In this section we learn how to use modules - ready-to-use collections of functions that provide good-quality code for common tasks. We’ll also learn how to create our own modules to package up reusable code. One of Python’s great strengths is the ready availability of modules for scientific computing.

Why Use Modules?

So far, almost everything we have used has been a core element of the Python language. While we now know enough to accomplish almost any computational task, writing all the code from scratch is time-consuming. One of Python’s great attractions for scientific development is the ready availability of modules - collections of functions that provide tested code for common tasks.

Importing Modules

To use code from a module, you need to import it. This is conventionally done at the start of your Python file. The simplest form is:

import <modulename>

Once imported, you access functions within the module by typing <modulename>.<function>(). For example, the datetime module provides functions to work with date and time information:

Here we’re using the datetime() function within the datetime module to calculate the time elapsed between two dates.

Try calculating different time intervals. Create datetime objects for: - Your birthday this year and your birthday next year - The start and end of this month - Any two significant dates you’re interested in

Import Shortcuts

Sometimes modules have long names and we expect to use them heavily. Python allows us to assign a shorthand name using as:

import matplotlib.animation as anim
a = anim.FuncAnimation(...)

Without as anim, we’d have to type the full matplotlib.animation.FuncAnimation(...) every time.

Selective Imports

Sometimes we only need one or two functions from a module. We can import specific functions using:

from <module> import <function1>, <function2>

This makes the functions available without needing to preface them with the module name:

Notice we don’t need to write math.exp() or math.sin() - the functions are directly available.

Import specific functions from the math module and use them to calculate: - The square root of 144 (use sqrt) - The value of π squared (use pi) - sin(π/2)

TipSolution
from math import sqrt, pi, sin

result1 = sqrt(144)
result2 = pi ** 2
result3 = sin(pi/2)

print(f"sqrt(144) = {result1}")
print(f"π² = {result2}")
print(f"sin(π/2) = {result3}")

Namespace Management

Python requires you to preface function calls with the module name (or import specific functions) to avoid namespace clashes - situations where two functions have the same name. For example, many modules might provide a function called save(), each doing something different.

However, if you really want to expose all functions in a module, Python allows:

from <module> import *

This uses the wildcard * to indicate that everything should be made available. This is generally best avoided unless you have a specific reason, as it can lead to confusing bugs.

Working with Documentation

An important skill is to work out what a module does and how to use it without being taught. Let’s practice with the datetime module.

Write a program that calculates how many days until your next birthday.

You’ll need to: 1. Get today’s date using datetime.datetime.now() 2. Create a date for your next birthday 3. Calculate the difference 4. Check if your birthday has already passed this year

NoteHint

If your birthday has already passed this year, you’ll need to calculate for next year. You can check if birthday_this_year < today and if so, add 1 to the year.

TipSolution
import datetime

today = datetime.datetime.now()
birth_month = 3
birth_day = 15

birthday_this_year = datetime.datetime(today.year, birth_month, birth_day)

if birthday_this_year < today:
    next_birthday = datetime.datetime(today.year + 1, birth_month, birth_day)
else:
    next_birthday = birthday_this_year

days_until = (next_birthday - today).days
print(f"Days until next birthday: {days_until}")

NumPy: The Foundation of Scientific Python

An essential module for scientists is NumPy (Numerical Python). It provides tools and data structures for working with numerical data and implementing matrix-vector calculations.

It’s conventional to use import numpy as np:

NumPy includes comprehensive mathematical functions:

  • Trigonometric: np.sin(), np.cos(), np.tan()
  • Inverse trig: np.arcsin(), np.arccos(), np.arctan(), np.arctan2()
  • Hyperbolic: np.sinh(), np.cosh(), np.tanh()
  • Exponential/Log: np.exp(), np.log(), np.log10()

NumPy Arrays: The Core Data Structure

The core feature of NumPy is the array data type, which allows structured grids of data to be accessed, transformed, and used efficiently. NumPy arrays are the standard for numerical data in Python.

Creating Arrays from Lists

Creating Standard Arrays

Creating Sequences

Key array creation functions:

  • np.ones(dims) - Array filled with 1s
  • np.zeros(dims) - Array filled with 0s
  • np.eye(N) - N×N identity matrix
  • np.arange(start, stop, step) - Sequence like range()
  • np.linspace(start, stop, N) - N evenly-spaced points

Create the following arrays:

  1. A 5×5 array of zeros
  2. An array of numbers from 10 to 50 in steps of 5
  3. An array of 11 evenly spaced points between 0 and 2π
  4. A 3×3 identity matrix
TipSolution
import numpy as np

zeros_array = np.zeros([5, 5])
sequence = np.arange(10, 55, 5)
points = np.linspace(0, 2*np.pi, 11)
identity = np.eye(3)

print("Zeros shape:", zeros_array.shape)
print("Sequence:", sequence)
print("Identity:\n", identity)

Accessing Array Elements

Array elements are accessed using [...] with zero-based indices. Use : for all elements in a dimension:

Array Operations

NumPy operations work element-wise on arrays:

Reading and Writing Data Files

NumPy provides convenient functions for file I/O:

If your file has header rows, use skiprows=n:

data = np.loadtxt('datafile.txt', skiprows=2)

Create a 2D array of your choice, save it to a file, and load it back. Verify they match.

TipSolution
import numpy as np

my_array = np.array([[1, 2], [3, 4], [5, 6]])
np.savetxt('test_array.txt', my_array)
loaded_array = np.loadtxt('test_array.txt')

print("Arrays match:", np.allclose(my_array, loaded_array))
print("Original:\n", my_array)
print("Loaded:\n", loaded_array)

Creating Your Own Modules

You can create your own modules to package up functions you use regularly. This is much better than copying code between files.

To create a module:

  1. Create a file named <module_name>.py
  2. Add your function definitions
  3. Save it in your working directory
  4. Import with import <module_name>

Example: Create a file called birthday_utils.py:

# birthday_utils.py
import datetime

def days_until_birthday(birth_month, birth_day):
    """Calculate days until next birthday.

    Parameters
    ----------
    birth_month : int
        Month of birth (1-12)
    birth_day : int
        Day of birth (1-31)

    Returns
    -------
    int
        Number of days until next birthday
    """
    today = datetime.datetime.now()
    birthday_this_year = datetime.datetime(today.year, birth_month, birth_day)

    if birthday_this_year < today:
        next_birthday = datetime.datetime(today.year + 1, birth_month, birth_day)
    else:
        next_birthday = birthday_this_year

    return (next_birthday - today).days

Then in your main code:

import birthday_utils

days = birthday_utils.days_until_birthday(3, 15)
print(f"Days until birthday: {days}")
NoteContributing to Python

If you create a significant module, you can contribute to the community through PyPI (Python Package Index). Python thrives on open-source contributions!

Further information: Python modules documentation

Summary

In this section we learned:

  • How to import modules with import
  • Using aliases with import ... as
  • Selective imports with from ... import
  • Working with NumPy arrays
  • Creating our own modules

Modules are fundamental to Python programming. The next exercises will explore NumPy and SciPy in much more detail!

WarningCoding scratch space