Creating a to-do app in Python was one of my recent projects, and it was an enriching experience that evolved over time. Initially, I started with simpler functions, focusing on getting the app to run smoothly in the console. As days passed, I refined and optimized the code, leading to the final version I'm sharing here. While I started with PyCharm, I encountered performance issues like overheating, so I'd recommend using VS Code instead for a smoother experience.
Why Build a To-Do App?
A to-do app might seem like a basic project, but it's a fantastic way to apply and improve your programming skills. It involves working with file handling, loops, conditional statements, and functions—all essential concepts in Python. Plus, the end product is something practical that you can actually use in your daily life.
Breaking Down the Code: A Step-by-Step Explanation
Let's dive into the code, and I'll walk you through my thought process at each stage.
- Setting Up the Environment:
import functions
import time
now = time.strftime("%b %d, %Y %H:%M:%S")
print("It is", now)
print("Routine checkup")
Why This?
I wanted the app to feel personal, so I added a timestamp at the start. It gives a real-time feel and serves as a gentle reminder of when you last checked your tasks. Importing the functions module keeps the main file clean and organized by handling file operations separately.
- Adding Tasks:
if user_action.startswith('add'):
todo = user_action[4:]
todos = functions.get_todos()
todos.append(todo + '\n')
functions.write_todos(todos)
Why This?
Initially, I experimented with different ways to add tasks. The approach I settled on—using string slicing—ensures that the app is user-friendly. It allows users to type "add " without needing to follow a rigid format. By appending a newline character (\n), the tasks are neatly stored in the text file, ensuring proper formatting.
3.Showing Tasks:
elif user_action.startswith('show'):
todos = functions.get_todos()
for index, item in enumerate(todos):
item = item.strip('\n')
row = f'{index + 1} - {item}'
print(row)
Why This?
Displaying tasks might seem straightforward, but it's crucial to ensure clarity. I used enumerate() to list tasks with numbers, making it easy to reference them later. Removing newline characters during display ensures the output is clean and readable.
4. Editing Tasks:
elif user_action.startswith('edit'):
try:
number = int(user_action[5:]) - 1
todos = functions.get_todos()
new_todo = input("Enter new todo: ") + '\n'
todos[number] = new_todo
functions.write_todos(todos)
except ValueError:
print("Oops! Your command is invalid.")
continue
Why This?
Editing was one of the trickier features to implement. The main challenge was managing user input and ensuring the correct task was updated. I chose to subtract 1 from the task number to align with Python's zero-based indexing. This choice simplifies coding but might require a brief explanation for users.
5. Completing Tasks:
elif user_action.startswith('complete'):
try:
number = int(user_action[9:])
todos = functions.get_todos()
todo_to_remove = todos.pop(number - 1).strip('\n')
functions.write_todos(todos)
print(f'Todo "{todo_to_remove}" was successfully removed.')
except IndexError:
print("The task number is not in your list.")
continue
Why This?
Completing a task involves removing it from the list, which brings up the challenge of managing list indices. By using .pop(), I was able to remove tasks efficiently, and the app confirms the deletion to avoid any confusion. Handling potential errors, like an IndexError, ensures that the app remains robust even with incorrect input.
6. Exiting the App:
elif user_action.startswith('exit'):
break
Why This?
The exit function is simple but essential. It gracefully terminates the loop, ending the session while ensuring that no tasks are lost in the process.
7.Functions File: Keeping It Organized
FILEPATH='todos.txt'
def get_todos(file_path=FILEPATH):
with open(file_path, 'r') as file_local:
todos_local = file_local.readlines()
return todos_local
def write_todos(todos_arg, file_path=FILEPATH):
with open(file_path, 'w') as file_local:
file_local.writelines(todos_arg)
Why This?
Splitting file operations into a separate functions.py file kept the main script clean and easy to read. It also makes it easier to debug and scale the app. By abstracting these operations, I ensured that the main logic focused on user interaction, while the functions file handled data persistence.
Final Thoughts
Building this to-do app was a fantastic learning experience. I encourage anyone interested in Python to try building something similar. Start simple, test your code, and gradually add features. Remember, it's not just about writing code—it's about understanding why you choose certain approaches and how they contribute to a more efficient and user-friendly program. And if you're using PyCharm and facing performance issues, give VS Code a try—it might just make your coding journey a little smoother.
Top comments (0)