Table of Contents
Planning a Simple To-Do List Program
A to-do list app is a classic beginner project: it’s small, useful, and lets you practice user input, lists, conditions, loops, and files (if you want to save tasks).
In this chapter you’ll:
- Design a text-based to-do list
- Build a basic version that runs while the program is open
- Add features: marking done, deleting tasks
- Optionally, save and load tasks from a file
You can type and run all examples in a single .py file.
Designing the Program (Before Coding)
A basic to-do list program usually needs to:
- Store tasks (somewhere in memory, usually a list)
- Show tasks to the user
- Add new tasks
- Mark tasks as done (optional but very useful)
- Delete tasks (optional)
- Keep running until the user chooses to exit
A simple text menu is enough:
1– Show tasks2– Add task3– Mark task as done4– Delete task5– Quit
You don’t need all of these at once. Start small and add features step by step.
Step 1: Representing Tasks
We need a way to store each task. For a very first version, each task can just be a string in a list:
- A list named
tasks - Each item is a piece of text:
"Buy milk","Study Python"
Later, we can add a “done/not done” status.
Basic structure:
tasks = []
# add a task
tasks.append("Buy milk")
# show all tasks
for task in tasks:
print(task)This gives you a simple in-memory list. When the program ends, the list is lost (we’ll fix that later with files).
Step 2: A Simple Menu Loop
To make a usable to-do list, we’ll use a loop that:
- Prints a menu
- Asks the user what they want to do
- Runs the chosen option
- Repeats until the user chooses to quit
tasks = []
while True:
print("\nTo-Do List")
print("1. Show tasks")
print("2. Add task")
print("3. Quit")
choice = input("Choose an option (1-3): ")
if choice == "1":
print("Showing tasks...")
elif choice == "2":
print("Adding a task...")
elif choice == "3":
print("Goodbye!")
break
else:
print("Invalid choice, please try again.")This is the “skeleton” of the program. Now we fill in the parts for showing and adding tasks.
Step 3: Showing and Adding Tasks
Showing all tasks with numbers
It’s helpful to number tasks so the user can refer to them later:
def show_tasks(tasks):
if not tasks: # list is empty
print("No tasks yet!")
return
print("\nYour tasks:")
for index, task in enumerate(tasks, start=1):
print(f"{index}. {task}")enumerate(tasks, start=1)gives you both the position and the task text.- We start at 1 because that’s more natural for users than starting at 0.
Adding a new task
A simple function for adding a task:
def add_task(tasks):
new_task = input("Enter a new task: ").strip()
if new_task == "":
print("Task cannot be empty.")
return
tasks.append(new_task)
print("Task added.")Now connect these functions to the menu loop:
tasks = []
def show_tasks(tasks):
if not tasks:
print("No tasks yet!")
return
print("\nYour tasks:")
for index, task in enumerate(tasks, start=1):
print(f"{index}. {task}")
def add_task(tasks):
new_task = input("Enter a new task: ").strip()
if new_task == "":
print("Task cannot be empty.")
return
tasks.append(new_task)
print("Task added.")
while True:
print("\nTo-Do List")
print("1. Show tasks")
print("2. Add task")
print("3. Quit")
choice = input("Choose an option (1-3): ")
if choice == "1":
show_tasks(tasks)
elif choice == "2":
add_task(tasks)
elif choice == "3":
print("Goodbye!")
break
else:
print("Invalid choice, please try again.")This is already a working to-do list (without saving or marking done).
Step 4: Marking Tasks as Done
We want to track whether a task is complete. Two simple options:
- Store tasks as strings, and decorate them
Example:"Buy milk [DONE]" - Store tasks as dictionaries
Example:{"text": "Buy milk", "done": False}
The second option is cleaner. Let’s switch to that.
Changing task structure
Instead of:
tasks.append(new_task) # a stringUse:
tasks.append({"text": new_task, "done": False})
Update show_tasks to display [ ] or [x]:
def show_tasks(tasks):
if not tasks:
print("No tasks yet!")
return
print("\nYour tasks:")
for index, task in enumerate(tasks, start=1):
status = "[x]" if task["done"] else "[ ]"
print(f"{index}. {status} {task['text']}")Now add a function to mark one task as done:
def mark_task_done(tasks):
if not tasks:
print("No tasks to mark as done.")
return
show_tasks(tasks)
choice = input("Enter the number of the task to mark as done: ")
if not choice.isdigit():
print("Please enter a valid number.")
return
index = int(choice) - 1 # convert to list index
if index < 0 or index >= len(tasks):
print("Task number out of range.")
return
tasks[index]["done"] = True
print(f"Marked task {index + 1} as done.")Add this option to the menu:
while True:
print("\nTo-Do List")
print("1. Show tasks")
print("2. Add task")
print("3. Mark task as done")
print("4. Quit")
choice = input("Choose an option (1-4): ")
if choice == "1":
show_tasks(tasks)
elif choice == "2":
add_task(tasks)
elif choice == "3":
mark_task_done(tasks)
elif choice == "4":
print("Goodbye!")
break
else:
print("Invalid choice, please try again.")Now tasks stay “done” as long as the program is running.
Step 5: Deleting Tasks
Deleting lets you remove tasks completely.
We can reuse the same style of input checking from marking done.
def delete_task(tasks):
if not tasks:
print("No tasks to delete.")
return
show_tasks(tasks)
choice = input("Enter the number of the task to delete: ")
if not choice.isdigit():
print("Please enter a valid number.")
return
index = int(choice) - 1
if index < 0 or index >= len(tasks):
print("Task number out of range.")
return
removed = tasks.pop(index)
print(f"Deleted task: {removed['text']}")Update the menu again:
while True:
print("\nTo-Do List")
print("1. Show tasks")
print("2. Add task")
print("3. Mark task as done")
print("4. Delete task")
print("5. Quit")
choice = input("Choose an option (1-5): ")
if choice == "1":
show_tasks(tasks)
elif choice == "2":
add_task(tasks)
elif choice == "3":
mark_task_done(tasks)
elif choice == "4":
delete_task(tasks)
elif choice == "5":
print("Goodbye!")
break
else:
print("Invalid choice, please try again.")At this point, you have a fully interactive to-do list while the program is running.
Step 6: Saving and Loading Tasks (Optional)
Right now, tasks disappear when you close the program. To keep them, we can:
- Write them to a file when the user quits
- Read them from the file when the program starts
We’ll use a plain text file with one task per line.
Simple text format
We need to save both the text and the done status. One simple format:
0;Buy milk→ not done1;Learn Python→ done
Where:
- The first part is
0or1(0= not done,1= done) - Then a
; - Then the task text
Saving tasks to a file
def save_tasks(tasks, filename="tasks.txt"):
with open(filename, "w", encoding="utf-8") as file:
for task in tasks:
done_flag = "1" if task["done"] else "0"
line = done_flag + ";" + task["text"] + "\n"
file.write(line)
print("Tasks saved.")Loading tasks from a file
def load_tasks(filename="tasks.txt"):
tasks = []
try:
with open(filename, "r", encoding="utf-8") as file:
for line in file:
line = line.rstrip("\n")
if ";" not in line:
continue # skip invalid lines
done_flag, text = line.split(";", 1)
task = {
"text": text,
"done": (done_flag == "1")
}
tasks.append(task)
except FileNotFoundError:
# No saved tasks yet
tasks = []
return tasksNow use these in your main program:
def show_tasks(tasks):
if not tasks:
print("No tasks yet!")
return
print("\nYour tasks:")
for index, task in enumerate(tasks, start=1):
status = "[x]" if task["done"] else "[ ]"
print(f"{index}. {status} {task['text']}")
def add_task(tasks):
new_task = input("Enter a new task: ").strip()
if new_task == "":
print("Task cannot be empty.")
return
tasks.append({"text": new_task, "done": False})
print("Task added.")
def mark_task_done(tasks):
if not tasks:
print("No tasks to mark as done.")
return
show_tasks(tasks)
choice = input("Enter the number of the task to mark as done: ")
if not choice.isdigit():
print("Please enter a valid number.")
return
index = int(choice) - 1
if index < 0 or index >= len(tasks):
print("Task number out of range.")
return
tasks[index]["done"] = True
print(f"Marked task {index + 1} as done.")
def delete_task(tasks):
if not tasks:
print("No tasks to delete.")
return
show_tasks(tasks)
choice = input("Enter the number of the task to delete: ")
if not choice.isdigit():
print("Please enter a valid number.")
return
index = int(choice) - 1
if index < 0 or index >= len(tasks):
print("Task number out of range.")
return
removed = tasks.pop(index)
print(f"Deleted task: {removed['text']}")
def save_tasks(tasks, filename="tasks.txt"):
with open(filename, "w", encoding="utf-8") as file:
for task in tasks:
done_flag = "1" if task["done"] else "0"
line = done_flag + ";" + task["text"] + "\n"
file.write(line)
print("Tasks saved.")
def load_tasks(filename="tasks.txt"):
tasks = []
try:
with open(filename, "r", encoding="utf-8") as file:
for line in file:
line = line.rstrip("\n")
if ";" not in line:
continue
done_flag, text = line.split(";", 1)
task = {
"text": text,
"done": (done_flag == "1")
}
tasks.append(task)
except FileNotFoundError:
tasks = []
return tasks
# Main program
tasks = load_tasks()
while True:
print("\nTo-Do List")
print("1. Show tasks")
print("2. Add task")
print("3. Mark task as done")
print("4. Delete task")
print("5. Save and quit")
choice = input("Choose an option (1-5): ")
if choice == "1":
show_tasks(tasks)
elif choice == "2":
add_task(tasks)
elif choice == "3":
mark_task_done(tasks)
elif choice == "4":
delete_task(tasks)
elif choice == "5":
save_tasks(tasks)
print("Goodbye!")
break
else:
print("Invalid choice, please try again.")Now your to-do list remembers tasks between runs.
Step 7: Possible Extensions
Once the basic version works, you can extend it in many ways. Some ideas:
- Edit a task: change its text
- Show only incomplete tasks
- Show statistics: number of tasks, number done
- Due dates or priorities: add more fields to each task dictionary
- Sort tasks: for example, incomplete first
- Confirm deletes: ask “Are you sure?” before deleting
Each new feature is a chance to practice functions, input handling, and data structures.
Summary
By building this to-do list, you practiced:
- Using a loop to create a menu
- Storing structured data in lists of dictionaries
- Reading and validating user input
- Modifying items in a list (marking done, deleting)
- Saving and loading data with files
This project combines many basic Python skills into a single, useful program you can keep improving as you learn more.