Modules#

Author: Mike Wood

Learning objectives: By the end of this notebook, you should be able to:

  1. Import common built-in Python modules

  2. Write your own module with functions designed for a particular task

  3. Import custom modules into a Jupyter Notebook

Common Built-In Python Modules#

Python has many built-in modules that can be utilized in any program - no installation necessary!

To import a built-in module, use the the import statement at the top of your script (or Jupyter notebook)

The time module#

The time module provides the functionality to access your machine’s timing. For example, it is often used to keep track of how long a particular piece of code takes to run.

# import the time module
import time

# use the time module to see how long it takes to count the numbers between 1 and N
# start be defining N
N = 10000

# store the time at the beginning of the function using the time module
start = time.time()

# run the counting loop
sum = 0
for i in range(N):
    sum += i
    
# store the time at the end of the function using the time module
end = time.time()

# print the elapsed time
print('Elapsed time: '+str(end - start)+' seconds')
Elapsed time: 0.0014920234680175781 seconds

The datetime module#

The datetime module provides functionality to track calendar dates and differences therein.

# import the datetime module
import datetime

# determine how long its been since you started your first semester in college

# define a datimetime object for your first semester
start_date = datetime.date(2023,8,26)

# define a datetime object for today
todays_date = datetime.date.today()

# find the time since you started
difference = todays_date - start_date

# print the number of days
print(difference)
614 days, 0:00:00

The math and cmath modules#

The math module provides functions to calculate standard mathematical functions. For example, it can be used to calculate exponentials and trignometric functions:

# import the math module
import math

# calculate the sine of pi/4
print('sin(\u03C0/4) =', math.sin(math.pi/4))

# calculate the expnential of pi/4
print('exp(\u03C0/4) =', math.exp(math.pi/4))

# calculate the natural logarithm of 3
print('ln(3) =', math.log(3))
sin(Ο€/4) = 0.7071067811865475
exp(Ο€/4) = 2.1932800507380152
ln(3) = 1.0986122886681098

The cmath functions can be used to calculate complex-values functions. To define a complex number, use the complex genertor function as follows:

z = complex(<real part>,<complex part>)

In other words,

\( z = x + iy \)

For example, we can test out one of the coolest identities in all of math:

\( e^{-ix} = cos(x) + isin(x)\)

# import the complex math module
import cmath

## define a value for x at pi/4
z = math.pi
i = complex(0,1)

## compute the left-hand side of the equation
LHS = cmath.exp(i*z)

## compute the right-hand side of the equation
RHS = cmath.cos(z) + i*cmath.sin(z)

# check whether the two numbers are equivalent
print(LHS==RHS,'(!)')
True (!)

The random module#

The random module provides functionality to generate (pseudo) random numbers:

# import the random module
import random as rn

# create a random integer between 1 and 10
print('Random integer between 1 and 10:',rn.randint(1,10))

# create a random float between 1 and 10
print('Random float between 1 and 10:',rn.uniform(1,10))

# sample the gaussian (aka normal) distribution
# the default values for the mean (mu) and the stardard deviation (sigma) are 0 and 1
print('Random sample from a Gaussian distribution:',rn.gauss(mu=0, sigma=1))
Random integer between 1 and 10: 6
Random float between 1 and 10: 5.16456819567339
Random sample from a Gaussian distribution: 2.756885464194921

Modules for the file system (see next notebook)#

  • os: basic operating system functions

  • shutil: functions for copying, etc

List of all built-in modules#

A list of all built-in modules can be accessed in the Python documentation at https://docs.python.org/3/py-modindex.html

πŸ€” Mini-Exercise#

Goal: Create an approximation to the sine function using polynomials. Calculate the root mean square error of the calculation for 100 random (float) values between -2 and 2.

The sine of a number can be estimated with the first four terms of its Taylor expansion as:

\(sin(x) \approx x - \frac{x^3}{6} + \frac{x^5}{120} - \frac{x^7}{5040}\)

The root mean square error (RMSE) is calculated as

\(RMSE = \sqrt{\frac{1}{N} \sum_{i=1}^{N} (e_i - t_i)^2}\)

where \(N\) is the number of points, \(e_i\) is the \(i\)th estimated value, and \(t_i\) is the \(i\)th true value.

# import the math and random modules
import math
import random

# define your approximate to sin in a function called sine_poly
def sine_poly(x):
    value = x - x**3/6 + x**5/120 - x**7/5040
    return value

# write a loop to calculate the root mean square error for 100 values
sum_of_squares = 0
N = 100
for i in range(N):
    x = random.uniform(-2,2)
    t_i = math.sin(x)
    e_i = sine_poly(x)
    sum_of_squares += (t_i - e_i)**2
RMSE = math.sqrt(sum_of_squares/N)

# print the RMSE value
print('RMSE of approximation:',RMSE)
RMSE of approximation: 0.0002820620965953877

Generating a custom module#

Python has a lot of very useful modules that are built-in with its standard distribution. However, as you begin to develop code and work on your own projects, you will want to start generating modules that can be used for your particular purpose.

For this example, it is recommend that you shift over to an Integrated Development Environment (IDE). Two common IDEs used by Python developers are:

In the IDE, create a new file called test_module.py in the same location as this notebook and write two new functions for your first and last name as follows:

def first_name():
    print('Mike')

def last_name():
    print('Wood')

To import a custom module into a Jupyter notebook, use the same syntax as above - use the import statment. The module name is given by the file name (without the py extension). For example, we can import the test_module module we created below:

# import the test module
import test_module as tm

# call the function from the test module
tm.first_name()
tm.last_name()
Mike
Wood

Note that the functions in the cell block above are not the functions in the previous cell block - they are imported from the module and are preceded by the tm alias.

πŸ€” Check your understanding#

How can you edit the test_module to create a new function for middle_name()?

Note

When you change a module outside of a Jupyter Notebook, you need to do one of two things to implement the changes: 1) restart your kernel or 2) use the importlib package by importing the package (import importlib) and reloading your package (tm = importlib.reload(tm)).

πŸ€” Try it for yourself#

Goal: Complete the astrology module provided with this notebook HERE by filling in the remainging functions in the astrology.py file.

The astrology module has two functions:

  1. birthday_to_sign(month, day) - a function to return the astrological sign corresponding to a given birthday

  2. sign_to_birthday_range(sign) - a function to return the birthday range for a given sign

The instructions for generating the module are provided in the comments of the separate file astrology.py. Be sure to edit this file and test it for a range of birthdays and signs. The following code shows how the two functions should operate:

# import the astrology module - give it an alias if you'd like
import astrology as astro
# test the birthday_to_sign function
sign = astro.birthday_to_sign(month=9, day=1)
print('The sign for a person born on September 1st is '+sign)
The sign for a person born on September 1st is Virgo
# test the sign_to_birthday_range function
date_range = astro.sign_to_birthday_range(sign='Gemini')
print('The Gemini sign corresonds to birthdays in the range '+
      str(date_range[0])+'/'+str(date_range[1])+' to '+str(date_range[2])+'/'+str(date_range[3]))
The Gemini sign corresonds to birthdays in the range 5/21 to 6/21