Skip to content

Python: A Beginner's Tutorial

Python is a readable, general-purpose programming language used for data analysis, automation, simulation, machine learning, and scientific computing. On Deceema, a tested Python program can move from a tiny local example to a repeatable Slurm job without changing its core logic.

This tutorial assumes no programming experience. It uses Python's standard library so you can learn the language and workflow before adding packages.

By the end, you will be able to:

  • Run Python interactively and from a script.
  • Work with variables, types, collections, conditions, and loops.
  • Write functions and import modules.
  • Read and write text and CSV files safely.
  • Understand exceptions and tracebacks.
  • Build a command-line program with explicit inputs and outputs.
  • Create a virtual environment and record dependencies.
  • Run a tested Python workflow through Slurm.

Before you begin

Complete Linux (RHEL) and Bash first if terminals, paths, files, quoting, or scripts are unfamiliar. Work inside the disposable training directory created below.

1. Meet the Python Interpreter

Prepare the Deceema software environment and inspect Python:

$ module purge
$ module load deceema
$ python --version

The interpreter is the python program that reads and executes Python instructions. Record its version because behavior and available features can change between releases.

Term Plain-language meaning
Interpreter The program that executes Python code.
Expression Code that produces a value, such as 2 + 3.
Statement An instruction, such as assigning a variable.
Script A .py text file containing Python code.
Function Reusable code that can accept inputs and return a result.
Module Reusable Python code imported into a program.
Package An installable collection of modules.
Exception An object describing an error or unusual condition.
Traceback Python's report showing where an unhandled exception occurred.

Run one expression

$ python -c 'print(2 + 3)'
5

The -c option executes the following Python text. print() displays a value.

Try the interactive prompt

$ python
>>> 2 + 3
5
>>> print("Hello from Deceema")
Hello from Deceema
>>> exit()

The >>> prompt belongs to Python; do not type it when copying an example. Use the interactive prompt for tiny experiments, not for work that must be reproduced later.

2. Create a Project Workspace

$ mkdir -p "$HOME/training/python-beginner"/{data,src,logs,results}
$ cd "$HOME/training/python-beginner"
$ pwd

This layout separates source code, input data, logs, and results.

Create src/hello.py:

src/hello.py
message = "Hello from Python on Deceema"
print(message)

Run it:

$ python src/hello.py
Hello from Python on Deceema

Python executes a script from top to bottom. The first line assigns text to message; the second passes that value to print().

3. Learn Values, Variables, and Types

A value is data. A variable is a name referring to a value.

project = "deceema-training"  # str: text
sample_count = 4              # int: whole number
mean_value = 5.0              # float: decimal number
completed = True              # bool: True or False
missing = None                # NoneType: no value

Python names are case-sensitive: sample_count and Sample_Count are different names.

Inspect types:

$ python -c 'value = 5.0; print(type(value).__name__)'
float

Convert between types

Text read from a file or command line often needs conversion:

text = "42"
count = int(text)
measurement = float("3.14")
label = str(count)

Invalid conversions raise an exception:

$ python -c 'print(float("not-a-number"))'

Read the final line of the traceback first; it names the exception and usually states the immediate problem.

4. Work with Strings

Strings are sequences of text characters:

project = "Deceema"
message = f"Running on {project}"

print(message)
print(project.lower())
print(len(project))

An f-string inserts expressions inside {...}.

Useful string operations:

raw = "  alpha,beta,gamma  "
clean = raw.strip()
parts = clean.split(",")
joined = " | ".join(parts)
  • strip() removes surrounding whitespace.
  • split() creates pieces around a separator.
  • join() combines strings with a separator.

Strings are immutable: methods return new strings rather than changing the original value.

5. Calculate with Numbers

a = 10
b = 3

print(a + b)   # addition
print(a - b)   # subtraction
print(a * b)   # multiplication
print(a / b)   # floating-point division
print(a // b)  # floor division
print(a % b)   # remainder
print(a**b)    # exponentiation

Floating-point values have finite precision. For scientific results, choose appropriate numerical methods and tolerances instead of assuming every decimal calculation is exact.

6. Store Collections of Values

Lists

A list is ordered and mutable:

values = [2.0, 4.0, 6.0]
values.append(8.0)

print(values[0])   # first item
print(values[-1])  # last item
print(len(values))

Python indexes begin at zero.

Tuples

A tuple is ordered and immutable:

coordinates = (6.5, 3.2)
x, y = coordinates

Dictionaries

A dictionary maps unique keys to values:

summary = {
    "count": 4,
    "mean": 5.0,
}

print(summary["mean"])
summary["maximum"] = 8.0

Sets

A set stores unique values:

samples = {"alpha", "beta", "alpha"}
print(samples)  # alpha appears only once

Choose a collection based on meaning, not merely convenience.

7. Make Decisions with Conditions

Python uses indentation to define blocks:

temperature = 28.5

if temperature > 30:
    category = "high"
elif temperature >= 20:
    category = "moderate"
else:
    category = "low"

print(category)

Common comparisons:

Operator Meaning
== Equal values.
!= Not equal.
<, <= Less than; less than or equal.
>, >= Greater than; greater than or equal.
in Membership in a collection.
is None The object is the singleton None.

Combine Boolean expressions with and, or, and not.

Assignment is not comparison

= assigns a value. == compares two values. Python reports a syntax error in many places where these are accidentally confused.

8. Repeat Work with Loops

Loop over values

values = [2, 4, 6, 8]

for value in values:
    print(value, value**2)

Loop with a counter

for index, value in enumerate(values, start=1):
    print(f"{index}: {value}")

Build a new list

squares = [value**2 for value in values]

This is a list comprehension. Use it for a simple transformation; use a normal loop when the logic needs multiple steps or clearer diagnostics.

While loop

attempt = 1

while attempt <= 3:
    print(f"Attempt {attempt}")
    attempt += 1

Ensure a while condition can eventually become false.

9. Write Reusable Functions

def calculate_mean(values):
    """Return the arithmetic mean of a non-empty sequence."""
    if not values:
        raise ValueError("values cannot be empty")
    return sum(values) / len(values)


result = calculate_mean([2, 4, 6, 8])
print(result)
  • def defines the function.
  • values is a parameter.
  • The indented string documents the function.
  • return sends a value to the caller.
  • raise reports an invalid condition explicitly.

Add type hints to communicate expectations:

def calculate_mean(values: list[float]) -> float:
    if not values:
        raise ValueError("values cannot be empty")
    return sum(values) / len(values)

Type hints improve readability and tooling; Python does not enforce them by itself at runtime.

10. Import Standard-Library Modules

Python's standard library provides tested building blocks:

import statistics
from pathlib import Path

values = [2, 4, 6, 8]
print(statistics.fmean(values))
print(Path.cwd())
  • import statistics imports a module.
  • from pathlib import Path imports one name from a module.

Avoid naming your own script statistics.py, csv.py, or another imported module name because it can shadow the real module.

11. Read and Write Files with pathlib

Create training input:

$ printf '2\n4\n6\n8\n' > data/values.txt

Read it in Python:

from pathlib import Path

input_path = Path("data/values.txt")
lines = input_path.read_text(encoding="utf-8").splitlines()
values = [float(line) for line in lines if line.strip()]

print(values)

Write an output safely to a known directory:

from pathlib import Path

output_path = Path("results/message.txt")
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text("Analysis complete\n", encoding="utf-8")

Use explicit encodings for text files and explicit input/output paths for batch workflows.

12. Work with CSV Data

Create a small dataset:

$ printf 'sample,value\nalpha,2\nbeta,4\ngamma,6\ndelta,8\n' \
    > data/measurements.csv

Read rows with csv.DictReader:

import csv
from pathlib import Path

input_path = Path("data/measurements.csv")

with input_path.open(newline="", encoding="utf-8") as handle:
    rows = list(csv.DictReader(handle))

values = [float(row["value"]) for row in rows]
print(values)

The with statement closes the file even if reading raises an exception. DictReader names each field from the header rather than relying on column positions.

13. Understand Exceptions and Tracebacks

Exceptions separate normal results from failure conditions.

try:
    value = float("not-a-number")
except ValueError as error:
    print(f"Could not parse value: {error}")

Catch only exceptions you can handle meaningfully. Avoid this pattern:

try:
    run_analysis()
except Exception:
    pass

It hides the traceback, reports success incorrectly, and makes batch failures difficult to diagnose.

Read a traceback

  1. Start with the final line for the exception type and message.
  2. Read upward to the first frame in your own code.
  3. Inspect the values and assumptions on that line.
  4. Reproduce the error with the smallest possible input.

14. Create a Virtual Environment

A virtual environment isolates project packages from the base Python installation.

Create one outside the project data directory:

$ mkdir -p "$HOME/.venvs"
$ python -m venv "$HOME/.venvs/python-beginner"
$ source "$HOME/.venvs/python-beginner/bin/activate"
$ python -m pip --version

The shell prompt may change while the environment is active. Confirm which interpreter will run:

$ command -v python
$ python -c 'import sys; print(sys.executable)'

Leave the environment:

$ deactivate

Virtual environments are disposable and generally not portable. Keep a dependency specification so they can be recreated.

If a project has an approved requirements.txt, activate the environment and install it using the package source and network method supported by your organization:

$ python -m pip install -r requirements.txt

Do not use administrative installation or bypass network controls.

15. Accept Command-Line Arguments

A reusable analysis should not hard-code personal paths. Python's argparse module validates arguments and generates help.

Create src/arguments.py:

src/arguments.py
1
2
3
4
5
6
7
8
9
import argparse
from pathlib import Path


parser = argparse.ArgumentParser(description="Inspect an input file")
parser.add_argument("input", type=Path, help="path to the input file")
args = parser.parse_args()

print(f"Input: {args.input}")

Explore the automatic help and then provide a path:

$ python src/arguments.py --help
$ python src/arguments.py data/values.txt

16. Build a Complete Data-Summary Program

Create src/summarize.py:

src/summarize.py
#!/usr/bin/env python3
import argparse
import csv
import statistics
import sys
from pathlib import Path


def parse_args():
    parser = argparse.ArgumentParser(
        description="Summarize the value column in a CSV dataset."
    )
    parser.add_argument("input", type=Path, help="input CSV file")
    parser.add_argument("output", type=Path, help="output summary file")
    parser.add_argument(
        "--run-name", default="training-run", help="name recorded in output"
    )
    return parser.parse_args()


def read_values(path):
    if not path.is_file():
        raise FileNotFoundError(f"input file does not exist: {path}")

    values = []
    with path.open(newline="", encoding="utf-8") as handle:
        reader = csv.DictReader(handle)
        if reader.fieldnames is None or "value" not in reader.fieldnames:
            raise ValueError("input CSV must contain a 'value' column")

        for line_number, row in enumerate(reader, start=2):
            try:
                values.append(float(row["value"]))
            except (TypeError, ValueError) as error:
                raise ValueError(
                    f"invalid value on CSV line {line_number}: {row['value']!r}"
                ) from error

    if not values:
        raise ValueError("input CSV contains no data rows")
    return values


def summarize(values):
    return {
        "count": len(values),
        "mean": statistics.fmean(values),
        "minimum": min(values),
        "maximum": max(values),
    }


def write_summary(path, run_name, summary):
    path.parent.mkdir(parents=True, exist_ok=True)
    lines = [f"run={run_name}"]
    lines.extend(f"{name}={value}" for name, value in summary.items())
    path.write_text("\n".join(lines) + "\n", encoding="utf-8")


def main():
    args = parse_args()
    values = read_values(args.input)
    summary = summarize(values)
    write_summary(args.output, args.run_name, summary)
    print(f"Wrote {args.output}")


if __name__ == "__main__":
    try:
        main()
    except (FileNotFoundError, OSError, ValueError) as error:
        print(f"error: {error}", file=sys.stderr)
        raise SystemExit(1)

Run the program

$ python src/summarize.py \
    data/measurements.csv \
    results/summary.txt \
    --run-name first-analysis
$ cat results/summary.txt

Expected result:

run=first-analysis
count=4
mean=5.0
minimum=2.0
maximum=8.0

Test a failure path

$ python src/summarize.py data/missing.csv results/missing.txt
error: input file does not exist: data/missing.csv

The program reports a focused diagnostic to standard error and returns a non-zero status.

17. Test and Debug Python

Compile without executing

$ python -m py_compile src/summarize.py

No output means Python compiled the file successfully.

Add small assertions

Create src/test_summarize.py:

src/test_summarize.py
from summarize import summarize


result = summarize([2.0, 4.0, 6.0, 8.0])

assert result["count"] == 4
assert result["mean"] == 5.0
assert result["minimum"] == 2.0
assert result["maximum"] == 8.0

print("All checks passed")

Run it from src so the module can be imported:

$ cd src
$ python test_summarize.py
All checks passed
$ cd ..

For a growing project, move to an approved testing framework and keep tests small, deterministic, and independent of production data.

Debug with evidence

  • Read the complete traceback.
  • Print values with repr(value) when whitespace or types are unclear.
  • Reduce the input to the smallest failing case.
  • Check type(value) when a value behaves unexpectedly.
  • Use breakpoint() for interactive debugging only when appropriate; remove it before unattended Slurm execution.

18. Record the Environment

Record the interpreter:

$ python --version > logs/python-version.txt 2>&1
$ python -c 'import sys; print(sys.executable)' >> logs/python-version.txt

Inside an activated virtual environment, capture installed packages:

$ python -m pip freeze > requirements-lock.txt

Keep the source, job script, dependency file, input identifiers or checksums, Python version, job ID, logs, and output with the project record.

Never store passwords, access tokens, private keys, or credentials in source code, command arguments, dependency files, notebooks, or logs.

19. Run Python Through Slurm

Create scripts/python-job.sh:

scripts/python-job.sh
#!/bin/bash
#SBATCH --job-name=python-training
#SBATCH --account=PROJECT_CODE
#SBATCH --qos=QOS_NAME
#SBATCH --time=00:10:00
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1
#SBATCH --mem=1G
#SBATCH --output=logs/%x-%j.out
#SBATCH --error=logs/%x-%j.err

set -euo pipefail

module purge
module load deceema
source "$HOME/.venvs/python-beginner/bin/activate"

python src/summarize.py \
  data/measurements.csv \
  "results/slurm-${SLURM_JOB_ID}.txt" \
  --run-name "slurm-${SLURM_JOB_ID}"

Replace PROJECT_CODE and QOS_NAME with the matching values from your approved Deceema access. Submit from the project directory:

$ sbatch scripts/python-job.sh

Use the returned ID:

$ squeue --jobs=JOB_ID
$ sacct --jobs=JOB_ID --format=JobID,State,ExitCode,Elapsed,MaxRSS

Inspect the result and both logs after completion. The project-relative paths mean the submission directory is part of this workflow.

20. Write Python Responsibly on Deceema

  • Test with small, disposable data before scaling.
  • Make input, output, configuration, and random seeds explicit.
  • Do not run compute-intensive Python work directly on a login node.
  • Avoid loading an entire large dataset when streaming or chunking is suitable.
  • Never let many parallel tasks write to one ordinary output file unsafely.
  • Create one output location per run to prevent accidental replacement.
  • Pin or record package versions used for production results.
  • Use arrays or explicit argument lists rather than constructing code as text.
  • Preserve useful tracebacks; do not hide unexpected exceptions.
  • Keep secrets out of code, notebooks, arguments, and logs.

21. Final Project: Summarize Multiple Datasets

Extend the training into a program called src/summarize_many.py that:

  1. Accepts one output CSV and one or more input CSV files.
  2. Reuses read_values() and summarize() from summarize.py.
  3. Writes one result row per input file.
  4. Includes input filename, count, mean, minimum, and maximum.
  5. Stops with a clear non-zero failure if any input is invalid.
  6. Creates the output directory when necessary.

Create a second dataset:

$ printf 'sample,value\nepsilon,10\nzeta,20\n' > data/more.csv

One possible solution:

src/summarize_many.py
#!/usr/bin/env python3
import argparse
import csv
import sys
from pathlib import Path

from summarize import read_values, summarize


def parse_args():
    parser = argparse.ArgumentParser(description="Summarize multiple CSV files.")
    parser.add_argument("output", type=Path)
    parser.add_argument("inputs", nargs="+", type=Path)
    return parser.parse_args()


def main():
    args = parse_args()
    rows = []

    for input_path in args.inputs:
        result = summarize(read_values(input_path))
        rows.append({"input": input_path.name, **result})

    args.output.parent.mkdir(parents=True, exist_ok=True)
    fieldnames = ["input", "count", "mean", "minimum", "maximum"]
    with args.output.open("w", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(handle, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(rows)

    print(f"Wrote {args.output}")


if __name__ == "__main__":
    try:
        main()
    except (FileNotFoundError, OSError, ValueError) as error:
        print(f"error: {error}", file=sys.stderr)
        raise SystemExit(1)

Compile and run it:

$ python -m py_compile src/summarize_many.py
$ python src/summarize_many.py \
    results/all-summaries.csv \
    data/measurements.csv data/more.csv
$ cat results/all-summaries.csv

Expected data:

input,count,mean,minimum,maximum
measurements.csv,4,5.0,2.0,8.0
more.csv,2,15.0,10.0,20.0

You can now build a reproducible Python workflow

You have learned Python's core types and control flow, separated logic into functions and modules, handled files and errors, tested a result, captured the environment, and prepared the workflow for Slurm.

Python Cheat Sheet

Goal Python
Print a value print(value)
Assign a variable name = value
Format text f"Result: {value}"
Create a list items = [a, b, c]
Create a dictionary record = {"key": value}
Conditional if condition:
Loop for item in items:
Define a function def name(parameter):
Import a module import module
Read text Path(path).read_text(encoding="utf-8")
Handle a known error except ValueError as error:
Exit with failure raise SystemExit(1)
Compile a script python -m py_compile SCRIPT
Create an environment python -m venv PATH

Common Beginner Mistakes

Mistake Better habit
Mixing tabs and spaces Use four spaces for each indentation level.
Naming a script after an imported module Choose a project-specific filename.
Installing every project into one environment Create a virtual environment per compatible workflow.
Depending on interactive variables or notebook state Build a script from explicit inputs.
Hard-coding a username or project path Accept paths as arguments or configuration.
Testing only against full research data Start with a tiny representative dataset.
Catching every exception and doing nothing Handle only expected errors and preserve diagnostics.
Assuming the login environment exists in Slurm Load modules and activate the environment in the job script.
Saving code without versions or tests Capture the environment and a small verified case.

Completion Checklist

  • I can run Python interactively and from a script.
  • I understand common types, collections, conditions, loops, and functions.
  • I can import modules and avoid name shadowing.
  • I can read and write text and CSV files with explicit paths.
  • I can interpret a traceback and handle expected exceptions.
  • I can create and activate a virtual environment.
  • My program accepts command-line arguments and produces explicit output.
  • I compile and test with small data before Slurm submission.
  • I record Python and dependency versions for reproducibility.
  • I completed and verified the multi-dataset final project.

Continue Learning

Learn Slurm fundamentals Explore the full jobs guide

Official Python References