3  Advanced Python Tutorial

This tutorial builds upon the foundational concepts introduced in the basic Python tutorial, focusing on more advanced topics. It covers virtual environments for project isolation, installing external libraries using pip, and applying these skills to build a unit conversion script with the Pint library. Examples are provided to demonstrate practical implementation, including conversions for speed and pressure units.

3.1 Requirements

To follow this tutorial, ensure you have Python (version 3.10 or later) installed on your computer, as detailed in the basic tutorial. You will also need access to a terminal or command prompt for creating virtual environments and installing libraries. No additional IDE is required beyond what was recommended previously, though Positron or VS Code remains suitable.

3.2 Virtual Environments (.venv)

Virtual environments in Python allow you to create isolated spaces for projects, ensuring that dependencies (libraries and versions) do not conflict across different projects. This is particularly useful when working on multiple applications that require different library versions.

3.2.1 Why Use Virtual Environments?

  • Isolation: Each project can have its own set of installed packages without affecting the global Python installation.
  • Reproducibility: Share your project’s dependencies easily via a requirements.txt file.
  • Cleanliness: Avoid cluttering your system Python with project-specific libraries.

3.2.2 Creating a Virtual Environment

To create a virtual environment named .venv in your project directory, open a terminal and navigate to the desired folder, then run:

python -m venv .venv

This command generates a .venv directory containing an isolated Python interpreter and pip.

3.2.3 Activating the Virtual Environment

Activation makes the virtual environment’s Python and pip the default for your terminal session.

  • On macOS/Linux:

    source .venv/bin/activate
  • On Windows:

    .venv\Scripts\activate

Once activated, your terminal prompt will typically show (.venv) to indicate the active environment.

3.2.4 Deactivating the Virtual Environment

To exit the virtual environment and return to the global Python, simply run:

deactivate

3.3 Installing Libraries with pip

pip is Python’s package installer, used to download and install libraries from the Python Package Index (PyPI). Within an activated virtual environment, installations are confined to that environment.

3.3.1 Installing Pint

Pint is a library for handling physical quantities and unit conversions, ensuring dimensional consistency in calculations.

To install Pint, activate your virtual environment (as described above) and run:

pip install pint

This command downloads and installs Pint and its dependencies. To verify the installation, start Python in interactive mode (e.g., python) and import Pint:

import pint

If no errors occur, the installation is successful.

3.3.2 Managing Dependencies

To save your project’s dependencies (e.g., for sharing), generate a requirements.txt file:

pip freeze > requirements.txt

Others can recreate the environment by installing from this file:

pip install -r requirements.txt

3.3.3 Sample Requirements File

A requirements.txt file lists the libraries and their versions required for a project. Below is an example for a project using Pint:

pint>=0.23

Save this content in a file named requirements.txt in your project directory. You can install these dependencies in a new virtual environment using pip install -r requirements.txt. This ensures consistent library versions across different setups.

3.4 Building a Unit Conversion Script with Pint

Pint simplifies unit conversions by associating units with numerical values, automatically handling conversions and ensuring compatibility (e.g., preventing addition of length and mass).

3.4.1 Basic Usage of Pint

First, import Pint and create a UnitRegistry to manage units:

# Basic Usage of Pint
from pint import UnitRegistry

ureg = UnitRegistry()

# Define a quantity with units
length = 2.5 * ureg.meter

# Convert to another unit
length_in_feet = length.to(ureg.foot)
print(length_in_feet)  # Output: 8.202099737532808 foot

Pint supports a wide range of units, including length, mass, temperature, speed, and pressure. For temperature conversions, use the .to() method carefully, as some require delta considerations for differences versus absolute values.

3.4.2 Temperature Conversion

# Temperature Conversion

from pint import UnitRegistry

ureg = UnitRegistry()
Q_ = ureg.Quantity # shorthand

# === Absolute temperature conversions require .to() on a Quantity object ===
t_c = Q_(10, ureg.degC)
t_k = t_c.to(ureg.K)
t_f = t_c.to(ureg.degF)

print("Initial temperature:")
print(f"{t_c} = {t_k} = {t_f:.2f}")

t_c = Q_(5, ureg.degC)
t_k = t_c.to(ureg.K)
t_f = t_c.to(ureg.degF)

print("\nFinal temperature:")
print(f"{t_c} = {t_k} = {t_f:.2f}")

# === Delta temperatures (for differences) ===
delta_c = Q_(5, ureg.delta_degC)
delta_k = delta_c.to(ureg.kelvin)          # Use kelvin for differences
delta_f = delta_c.to(ureg.delta_degF)

print("\nTemperature differences:")
print(f"{delta_c} = {delta_k} = {delta_f}")

# === Difference between two absolute temperatures ===
t1_c = Q_(10, ureg.degC)
t2_c = Q_(5, ureg.degC)

delta_abs_c = t1_c - t2_c                 # 5 degC
delta_abs_k = delta_abs_c.to(ureg.kelvin) # 5 K
delta_abs_f = delta_abs_c.to(ureg.delta_degF) # 9 delta_degF

print("\nOr difference between 10 °C and 5 °C:")
print(f"{delta_abs_c} = {delta_abs_k} = {delta_abs_f}")

Output:

Initial temperature:
10 degree_Celsius = 283.15 kelvin = 50.00 degree_Fahrenheit

Final temperature:
5 degree_Celsius = 278.15 kelvin = 41.00 degree_Fahrenheit

Temperature differences:
5 delta_degree_Celsius = 5 kelvin = 9.0 delta_degree_Fahrenheit

Or difference between 10 °C and 5 °C:
5 delta_degree_Celsius = 5 kelvin = 9.0 delta_degree_Fahrenheit

Note that the conversion from Fahrenheit to Celsius is given:

\[ t_f = (t_c \times \frac{9}{5}) + 32 \]

and for temperature difference, the offset +32 does not apply:

\[ \Delta t_f = \Delta t_c \times \frac{9}{5} \]

3.4.3 Building the Script

Create a file named unit_converter.py in your project directory. The following script provides a command-line interface for converting various units (e.g., length, temperature, speed, pressure) using Pint. Activate your virtual environment, ensure Pint is installed, and add the code below:

# unit_converter.py
from pint import UnitRegistry, UndefinedUnitError, DimensionalityError
import sys

# Common unit aliases for applied mechanics
unit_aliases = {
    # Length / distance
    "m": "meter",
    "meter": "meter",
    "meters": "meter",
    "cm": "centimeter",
    "mm": "millimeter",
    "km": "kilometer",
    "ft": "foot",
    "inch": "inch",
    "in": "inch",
    "mi": "mile",

    # Force
    "n": "newton",
    "newton": "newton",
    "kgf": "kilogram_force",
    "kg_f": "kilogram_force",
    "lbf": "pound_force",
    "lb_f": "pound_force",

    # Pressure / stress
    "pa": "pascal",
    "kpa": "kPa",
    "mpa": "MPa",
    "bar": "bar",
    "psi": "psi",
    "atm": "atm",

    # Energy / work
    "j": "joule",
    "kj": "kilojoule",
    "cal": "calorie",
    "kcal": "kilocalorie",
    "ev": "electronvolt",
    "eV": "electronvolt",

    # Power
    "w": "watt",
    "kw": "kilowatt",
    "hp": "horsepower",

    # Mass
    "kg": "kilogram",
    "g": "gram",
    "lb": "pound",
    "lbs": "pound",
    "t": "ton",
    "slug": "slug",

    # Acceleration
    "m/s^2": "meter/second**2",
    "ft/s^2": "foot/second**2",
    "g": "9.80665*m/s**2",  # gravity acceleration

    # Torque / Moment
    "n*m": "newton*meter",
    "lbf*ft": "pound_force*foot",
    "kgf*m": "kilogram_force*meter",

    # Speed / velocity
    "m/s": "meter/second",
    "km/h": "km/h",
    "kph": "km/h",
    "mph": "mile/hour",
    "ft/s": "foot/second",
    "knot": "knot",

    # Temperature
    "degc": "degC",
    "degf": "degF",
    "celsius": "degC",
    "fahrenheit": "degF",
    "k": "kelvin",
    "delta_degC": "delta_degC",
    "delta_degF": "delta_degF"
}

def main():
    ureg = UnitRegistry()
    
    if len(sys.argv) != 4:
        print("Usage: python unit_converter.py <value> <from_unit> <to_unit>\n")
        print("Examples:")
        print("  python unit_converter.py 2.5 meter foot")
        print("  python unit_converter.py 100 degC degF")
        print("  python unit_converter.py 100 knot km/h")
        print("  python unit_converter.py 50 psi kPa")
        print("  python unit_converter.py 5000 hp kw")
        sys.exit(1)
    
    try:
        value = float(sys.argv[1])
        from_unit = sys.argv[2]
        to_unit = sys.argv[3]
        
        # Apply aliases if any
        from_unit = unit_aliases.get(from_unit.lower(), from_unit)
        to_unit = unit_aliases.get(to_unit.lower(), to_unit)
        
        # Use Quantity for proper temperature and unit handling
        quantity = ureg.Quantity(value, from_unit)
        converted = quantity.to(to_unit)
        
        # Rounded output
        print(f"{value} {from_unit} is {round(converted.magnitude, 4)} {to_unit}")
    
    except (UndefinedUnitError, DimensionalityError) as e:
        print(f"Error: {e}")
        print("Ensure units are valid and compatible (e.g., length to length, pressure to pressure).")
    except ValueError:
        print("Error: The value must be a number.")

if __name__ == "__main__":
    main()

3.4.4 Running the Script

Navigate to your project directory in the terminal, activate the virtual environment, and run:

python3 unit_converter.py

Output:

Usage: python unit_converter.py <value> <from_unit> <to_unit>

Examples:
  python unit_converter.py 100 km/h mph
  python unit_converter.py 16 knot km/h
  python unit_converter.py 3 m^3/min l/s
  python unit_converter.py 1000 kg/m^3 g/cm^3
  python unit_converter.py 7 bar psi
  python unit_converter.py 12 bar MPa
  python unit_converter.py 3000 kw hp

For temperature:

python3 unit_converter.py 100 degC degF

Output: 100.0 degC is 212.0 degF

For speed:

python3 unit_converter.py 100 knot km_per_hour

Output: 100.0 knot is 185.2 km/h

For pressure:

python3 unit_converter.py 50 psi kPa

Output: 50.0 psi is 344.7379 kPa

python3 unit_converter.py 2 bar psi

Output: 2.0 bar is 29.0075 psi

python3 unit_converter.py 3000 kw hp

Output: 3000.0 kilowatt is 4023.0663 horsepower

This script handles errors for invalid units, incompatible conversions (e.g., meters to kilograms), and non-numeric inputs.

3.5 Summary

This advanced tutorial explored virtual environments for project isolation, installing libraries like Pint using pip, and constructing a versatile unit conversion script. The script supports conversions for length, temperature, speed (e.g., knots to km/h), and pressure (e.g., psi to kPa, bar to psi), making it useful for scientific and engineering applications. For further exploration, consult the official Pint documentation or experiment with additional units and quantities.