Python: Functions, Modules, and Virtual Environments

Small experiments are easy to put in one file. Useful programs become easier to maintain when their work is divided into functions and modules. A virtual environment keeps each project's packages separate from the rest of the system.

Functions with Clear Inputs and Outputs

def celsius_to_fahrenheit(celsius):
    return celsius * 9 / 5 + 32

temperature = celsius_to_fahrenheit(18)
print(f"{temperature:.1f} F")

A function should usually do one job. Give it the values it needs as arguments and return the result instead of relying on global variables.

Type Hints

Type hints document what a function expects and returns. Python does not enforce them at runtime, but editors and checking tools can use them.

def describe_node(name: str, battery: int) -> str:
    return f"{name}: {battery}% battery"

print(describe_node("field-node-01", 87))

Modules

Any Python file can be imported as a module. Create weather.py:

def describe(temperature):
    if temperature < 0:
        return "freezing"
    if temperature > 25:
        return "warm"
    return "moderate"

Then use that function from another file:

import weather

print(weather.describe(18))

The Main Guard

When a file can be both imported and run directly, put its command-line behavior behind a main guard.

def main():
    print("This runs when the file is used as a program")

if __name__ == "__main__":
    main()

Virtual Environments

A virtual environment creates an isolated Python installation for one project. On Debian or another Unix-like system:

$ mkdir node-report
$ cd node-report
$ python3 -m venv .venv
$ . .venv/bin/activate
(.venv) $ python -m pip install --upgrade pip
(.venv) $ python --version
(.venv) $ deactivate

When the environment is active, python and pip refer to the project environment. Do not commit the .venv directory to Git; recreate it from a dependency list instead.

Dependencies and requirements.txt

When a project needs third-party packages, record them in a requirements file so another machine can reproduce the environment.

(.venv) $ python -m pip install meshtastic
(.venv) $ python -m pip freeze > requirements.txt

# On another machine:
$ python3 -m venv .venv
$ . .venv/bin/activate
(.venv) $ python -m pip install -r requirements.txt

Use python -m pip instead of a bare pip command. It makes clear which Python installation receives the package.

Testing a Function

A small assertion can catch a broken calculation before a larger program depends on it:

def celsius_to_fahrenheit(celsius):
    return celsius * 9 / 5 + 32

assert celsius_to_fahrenheit(0) == 32
assert round(celsius_to_fahrenheit(20), 1) == 68.0

For a larger project, move these checks into a test file and use Python's unittest module or a test runner. Keeping functions free of input and printing makes them much easier to test.

Project Layout

node-report/
├── .venv/
├── requirements.txt
├── README.md
└── src/
    ├── report.py
    └── formatters.py

Keep generated files, virtual environments, and secrets out of version control. A .gitignore entry for .venv/ and __pycache__/ is a good start.

References