Python Lab: Simple DBs

In this lab, you’ll be working on a simple “database” system consisting of dictionaries. The idea here is to understand some basic CRUD actions and how you can use data abstractions (dictionaries in this case) to represent redundant, similar data under a unified structure.

You’ll have to do some research about some Python syntax for this!

You can complete the Python lab by simply running your code and getting your outputs in the Jupyter notebook.

# Our "database" is a list of dictionaries, each representing a record (e.g., a student)
# Lists allow us to store multiple records in a single variable, making it easy to manage collections of data.
db = [
    {"name": "Alice", "age": 16, "grade": "A"},
    {"name": "Bob", "age": 17, "grade": "B"},
    {"name": "Charlie", "age": 16, "grade": "C"}
]

# Lists provide order and allow us to add, remove, or update records efficiently.
# Each element in the list is a dictionary, which abstracts the details of each student.

# Function to display all records
def display_db(database):
    print("All records in the list:")
    for i, record in enumerate(database):
        print(f"Index {i}: {record}")

# Function to add a new record (students: implement input and append logic)
def add_record(database, name=None, age=None, grade=None):
    # If values are provided use them; otherwise prompt the user.
    if name is None:
        name = input("Name: ").strip()
    if age is None:
        try:
            age = int(input("Age: ").strip())
        except Exception:
            age = None
    if grade is None:
        grade = input("Grade: ").strip()
    database.append({"name": name, "age": age, "grade": grade})
    print(f"Added record: name")

# Function to find a record by name (students: implement search logic)
def find_record(database, search_name):
    # Search for a record with matching name and print it
    for i, record in enumerate(database):
        if record.get("name") == search_name:
            print(f"Found record at index {i}: {record}")
            return i
    print(f"No record found with name: {search_name}")
    return None

# Function to update a record (students: implement update logic)
def update_record(database, search_name, new_name=None, new_age=None, new_grade=None):
    # Find record by name and update its fields
    for i, record in enumerate(database):
        if record.get("name") == search_name:
            print(f"Current record: {record}")
            # If new values are provided, use them; otherwise prompt and allow empty to keep
            if new_name is None:
                val = input(f"New name (enter to keep '{record['name']}'): ").strip()
                if val:
                    record['name'] = val
            else:
                record['name'] = new_name
            if new_age is None:
                val = input(f"New age (enter to keep '{record['age']}'): ").strip()
                if val:
                    try:
                        record['age'] = int(val)
                    except Exception:
                        pass
            else:
                record['age'] = new_age
            if new_grade is None:
                val = input(f"New grade (enter to keep '{record['grade']}'): ").strip()
                if val:
                    record['grade'] = val
            else:
                record['grade'] = new_grade
            database[i] = record
            print(f"Updated record at index {i}: {record}")
            return True
    print(f"No record found with name: {search_name} (nothing updated)")
    return False

# Function to delete a record (students: implement delete logic)
def delete_record(database, search_name):
    # Remove record with matching name from database
    for i, record in enumerate(database):
        if record.get('name') == search_name:
            removed = database.pop(i)
            print(f"Deleted record at index {i}: {removed}")
            return True
    print(f"No record found with name: {search_name} (nothing deleted)")
    return False

# Non-interactive demo calls so the notebook can run end-to-end without blocking stdin
display_db(db)
print('\n-- Demo: add_record --')
add_record(db, name="Diana", age=15, grade="B+")
print('\n-- Demo: find_record --')
find_record(db, "Diana")
print('\n-- Demo: update_record --')
update_record(db, "Diana", new_age=16, new_grade="A-")
print('\n-- Demo: delete_record --')
delete_record(db, "Charlie")
print('\n-- Final database state --')
display_db(db)

All records in the list:
Index 0: {'name': 'Alice', 'age': 16, 'grade': 'A'}
Index 1: {'name': 'Bob', 'age': 17, 'grade': 'B'}
Index 2: {'name': 'Charlie', 'age': 16, 'grade': 'C'}

-- Demo: add_record --
Added record: {'name': name, 'age': age, 'grade': grade}

-- Demo: find_record --
Found record at index 3: {'name': 'Diana', 'age': 15, 'grade': 'B+'}

-- Demo: update_record --
Current record: {'name': 'Diana', 'age': 15, 'grade': 'B+'}
Updated record at index 3: {'name': 'Shay', 'age': 16, 'grade': 'A-'}

-- Demo: delete_record --
Deleted record at index 2: {'name': 'Charlie', 'age': 16, 'grade': 'C'}

-- Final database state --
All records in the list:
Index 0: {'name': 'Alice', 'age': 16, 'grade': 'A'}
Index 1: {'name': 'Bob', 'age': 17, 'grade': 'B'}
Index 2: {'name': 'Shay', 'age': 16, 'grade': 'A-'}