Session 15: Importing Packages and Writing Packages#

Introduction#

So far we have mostly used the Python built-in functions - and this has allowed us to do quite a lot! However, the real power of Python comes from the large amount of additional functionality that can be used by importing these packages into your code. There are several hundred thousand packages available for all kinds of general and specialist purposes. Some of the more essential ones are installed by default with most Python installations, others first need to be installed. In this session we will first cover the general usage of packages and the Standard Library Packages. In the second part we will look at how to split our own code in several code files for better organisation and readability.

Part 1: Importing Packages#

Python packages are collections of modules (we’ll explain what these are in a minute) that provide additional functionality. By importing packages, we can access a wide range of tools and functions that extend the capabilities of our programs.

Task 1: Using the math Package#

  1. Create a New Python File:

    • Open Visual Studio Code (VS Code) or your preferred IDE.

    • Create a new file named math_import.py.

  2. Write the Following Code:

import math

# Calculate the square root of 16
sqrt_16 = math.sqrt(16)
print(f"The square root of 16 is {sqrt_16}")

# Calculate the sine of pi/2
sin_pi_over_2 = math.sin(math.pi / 2)
print(f"The sine of pi/2 is {sin_pi_over_2}")

# Calculate the natural logarithm of e
ln_e = math.log(math.e)
print(f"The natural logarithm of e is {ln_e}")
  1. Run the Code:

    • Save the file.

    • Run the script and observe the output.

Analysis#

  • Importing the Package: Statement import math imports the math package, giving us access to mathematical functions and constants.

  • Using math.sqrt(): As the name implies, this function calculates the square root of the parameter.

  • Using Constants: math.pi and math.e gives us convenient access to these fundamental mathematical constants.

  • Using Trigonometric and Logarithmic Functions: math.sin() and all of the other trigonometric functions are available. Same applies to math.log() and other logarithmic and exponential functions.

Task 2: Importing Specific Functions from a Package#

Instead of importing the entire math package, we’ll import only the functions we need.

  1. Update math_import.py and run it:

from math import sqrt, sin, pi, e, log

# Calculate the square root of 25
sqrt_25 = sqrt(25)
print(f"The square root of 25 is {sqrt_25}")

# Calculate the sine of pi/4
sin_pi_over_4 = sin(pi / 4)
print(f"The sine of pi/4 is {sin_pi_over_4}")

# Calculate the natural logarithm of e^2
ln_e_squared = log(e ** 2)
print(f"The natural logarithm of e^2 is {ln_e_squared}")

Analysis#

  • Importing Specific Functions:

from math import sqrt, sin, pi, e, log
  • This imports only the specified functions and constants from the math package.

  • Allows us to use sqrt instead of math.sqrt.

  • Note: There is no performance benefit here; it is mainly used to allow us to omit having to prefix the imported functions with math.* every time we use them.

Below is a selection of commonly default packages that are included in the Python Standard Library. These packages provide many useful features that do not require additional installations. Below is a list of some key packages that are typically included with Python by default:

Commonly Included Python Standard Library Packages#

  1. os: Provides functions to interact with the operating system (file handling, environment variables, etc.).

  2. sys: Provides access to system-specific parameters and functions, including command-line arguments.

  3. math: Provides basic mathematical functions like trigonometry, logarithms, etc.

  4. json: Enables parsing and generating JSON (JavaScript Object Notation) data.

  5. re: Provides regular expression matching operations.

  6. datetime: Provides classes for manipulating dates and times.

  7. subprocess: Allows you to spawn new processes, connect to input/output/error pipes, and obtain return codes.

  8. threading: Provides support for thread-based parallelism.

  9. time: Provides various time-related functions.

  10. http: A collection of modules for web-related tasks like sending HTTP requests (e.g., http.client and http.server).

  11. urllib: For handling URLs (fetching data from URLs, parsing URLs, etc.).

  12. csv: Helps to handle CSV (Comma-Separated Values) files.

  13. logging: Provides a flexible framework for outputting log messages.

  14. random: Provides tools to generate random numbers and make random selections.

  15. collections: Provides specialized container data types like namedtuples, deque, and OrderedDict.

  16. itertools: Provides tools for working with iterators.

  17. functools: Offers higher-order functions for functional programming.

  18. sqlite3: An interface for SQLite databases, allowing for lightweight database management.

  19. argparse: Provides a way to handle command-line arguments.

  20. io: Provides tools to work with I/O streams.

There is a lot of useful functionality in each of these packages, but unfortunately we do not have time to cover each in detail. We encourage you to look at the documentation (more on this later!) of some of these packages and see how they could be useful in something you might want to build.

Part 2: Installing External Packages#

While the Standard Library provides many useful modules, sometimes we need to use external packages that are not included by default. We can install these packages using package managers like pip (others exist such as anaconda or uv). You might remember we used pip in the very first session to install Jupyter Notebooks.

Task 3: Installing and Using the numpy Package#

  1. Installing numpy:

    • Open a terminal window.

    • Install numpy using pip by typing the following line and pressing Enter:

    pip install numpy
    
  2. Create a New File:

    • In VSCode IDE create a new file named numpy_example.py.

  3. Write the Following Code:

import numpy as np

# Create a numpy array
data = np.array([1, 2, 3, 4, 5])

# Calculate mean and standard deviation
mean = np.mean(data)
std_dev = np.std(data)

print(f"Data: {data}")
print(f"Mean: {mean}")
print(f"Standard Deviation: {std_dev}")
  1. Save the file and run it.

Analysis#

  • Installing Packages with pip:

    • pip is the Python built-in package manager that you may also use. We use it to install external packages.

    • Other package installers exist, such as conda which has been historically popular amongst scientific communities, or uv which is more modern and gaining popularity.

  • Importing numpy:

    import numpy as np
    
    • We import numpy and give it the alias np for convenience. This allows us to use np instead of numpy any time we want to use it in our code.

  • Using numpy Functions:

    • np.array: Creates a numpy array.

    • np.mean: Calculates the mean of the array.

    • np.std: Calculates the standard deviation.

Numpy has many more functions and is an extremely popular Python package, especially in scientific and engineering settings, so it is well worth the effort to become more familiar with its functions. You can find lots more information on how to use it and why you might want to use it on the official website, but we will be going through some of its features in a later session.

Part 3: Organizing Code into Multiple Files#

The import keyword is not only for importing Standard Libraries or installed packages - it can also be used to import code files written by ourselves! As our programs grow in size and complexity, it is often beneficial to organize code into multiple files or modules. This enhances readability and reusability.

Task 4: Creating and Importing a Custom Module#

  1. Create a New Directory:

    • In your project folder, create a new directory named chemistry_utils.

  2. Create a Module File:

    • Inside chemistry_utils, create a new file named calculations.py.

  3. Write the Following Code in calculations.py:

def calculate_moles(mass, molar_mass):
    """
    Calculate the number of moles given mass and molar mass.

    Parameters:
    mass (float): Mass of the substance in grams.
    molar_mass (float): Molar mass of the substance in g/mol.

    Returns:
    float: Number of moles.
    """
    return mass / molar_mass

def calculate_concentration(moles, volume):
    """
    Calculate the concentration of a solution.

    Parameters:
    moles (float): Number of moles of solute.
    volume (float): Volume of the solution in liters.

    Returns:
    float: Concentration in mol/L.
    """
    return moles / volume
  1. Create the Main Script:

    • In your main project folder, create a new file named solution_calculator.py.

  2. Write the Following Code in solution_calculator.py:

from chemistry_utils.calculations import calculate_moles, calculate_concentration

# Example usage
mass_of_solute = 5.0  # grams
molar_mass_of_solute = 58.44  # g/mol (e.g., NaCl)
volume_of_solution = 0.5  # liters

moles = calculate_moles(mass_of_solute, molar_mass_of_solute)
concentration = calculate_concentration(moles, volume_of_solution)

print(f"Moles of solute: {moles} mol")
print(f"Concentration of the solution: {concentration} mol/L")
  1. Run the Code:

    • Save both files.

    • Run solution_calculator.py.

Analysis#

  • Creating a Module: we created a new module (file) calculations.py inside the chemistry_utils package (folder containing module files).

    • Historically, a package folder had to contain a (usually empty) file named __init__.py to explicitly tell Python that this was a package. This isn’t always necessary these days, but it is useful to be aware of and in some cases (beyond the scope of this module) you will want to include it.

  • Defining Functions: the module contains functions for calculating moles and concentration.

  • Importing from a Module:

    from chemistry_utils.calculations import calculate_moles, calculate_concentration
    
    • We import the specific functions we need from our custom module.

  • Using Imported Functions:

    • We use calculate_moles and calculate_concentration in the main script.

Note

At this point it should be clear what the differece is between a package and a module, but just to be clear: a module is a file of python code that provides useful functionality, but isn’t itself a program to be run. A package is a collection of module files that are logically connected, typically stored together in a folder, that when required are installed together, as a unit. In session 17 you will bw introduced to an even higher level organisational structure - the library. If you still feel a little unsure, take a look at this article.

Task 5: Splitting Code into Multiple Modules#

  1. Add a New Module:

    • Inside chemistry_utils, create a new file named constants.py.

  2. Write the Following Code in constants.py:

    AVOGADRO_NUMBER = 6.02214076e23  # particles per mole
    
  3. Update calculations.py:

    • Modify calculations.py to use the constant:

    from .constants import AVOGADRO_NUMBER
    
    def calculate_number_of_particles(moles):
        """
        Calculate the number of particles given moles.
    
        Parameters:
        moles (float): Number of moles.
    
        Returns:
        float: Number of particles.
        """
        return moles * AVOGADRO_NUMBER
    
    
  4. Update solution_calculator.py:

    from chemistry_utils.calculations import (
      calculate_moles,
      calculate_concentration,
      calculate_number_of_particles,
      )
    
    # Example usage
    
    mass_of_solute = 5.0  # grams
    molar_mass_of_solute = 58.44  # g/mol (e.g., NaCl)
    volume_of_solution = 0.5  # liters
    
    moles = calculate_moles(mass_of_solute, molar_mass_of_solute)
    concentration = calculate_concentration(moles, volume_of_solution)
    particles = calculate_number_of_particles(moles)
    
    print(f"Moles of solute: {moles} mol")
    print(f"Concentration of the solution: {concentration} mol/L")
    print(f"Number of particles: {particles} particles")
    
  5. Run the Code:

    • Save all files.

    • Run solution_calculator.py.

Analysis#

  • Adding More Modules:

    • We added a constants.py module to store constants.

    • Because AVOGADRO_NUMBER is a constant, we name the variable in all capital letters.

      • This tells us visually that it is a constant, and is good naming practice.

  • Importing from Submodules:

    from .constants import AVOGADRO_NUMBER
    
  • Updating Functions:

    • We added a new function calculate_number_of_particles that uses Avogadro’s number inside our calculations.py module.

      • Note that we import from .constants here; the leading dot tells Python to look in the same package (folder) as the current file for a module called constants (the file constants.py).

  • Using New Functions:

    • In solution_calculator.py, we import and use the new function.

      • Since we are importing modules from inside the package (folder) chemistry_utils relative to the current file, we use this as our prefix when importing.

Conclusion#

In this session, we’ve explored:

  • Importing Packages:

    • How to import built-in packages like math and random.

    • Importing specific functions from packages.

    • Installing and using external packages like numpy.

  • Organizing Code:

    • Creating custom modules and packages.

    • Splitting code into multiple files for better organization.

By importing packages, we can leverage a vast ecosystem of existing code to enhance our programs. Organizing code into multiple files makes it more manageable, especially as projects grow in size.


Additional Practice#

  • Explore Other Standard Library Packages:

    • Look into packages like os, sys, datetime, and see how they can be used in your programs.

  • Create Your Own Packages:

    • Try organizing code from previous sessions into modules and packages.

  • Read Package Documentation:

    • Practice reading documentation to learn about the functionalities provided by different packages.

      • We will be going through this in more detail in a future session.