Cristhian Villegas
Backend14 min read8 views

Python Course #10: Final Project - Task Manager

Python Course #10: Final Project - Task Manager

Final Project: Task Manager in the Terminal - Part 10 of 10

Python Logo

We made it to the last article of the Python from Scratch Course! This is article 10 of 10, and it is time to put into practice everything you have learned throughout the course.

We are going to build a task manager (to-do list) that runs in the terminal. This project uses variables, functions, lists, dictionaries, object-oriented programming (OOP), file handling, and error handling — basically everything we have covered.

By the end you will have a complete, working program that you can use in your daily life and that proves you already know how to program in Python.

📌 Note: This project combines concepts from all 9 previous articles. If something is not clear, you can go back to the corresponding article to review.

Project Description

Our task manager will have the following features:

  • Add tasks with title and description
  • List all tasks showing their status (pending or completed)
  • Mark tasks as completed
  • Delete tasks
  • Search tasks by keyword
  • Save tasks to a JSON file so they are not lost when the program closes
  • Interactive menu with numbered options

The project will have 3 files:

File What it contains
models.py The Task class (data model)
task_manager.py The TaskManager class (business logic)
main.py The interactive menu (user interface)

Step 1: Project Structure

First, create a folder for the project and inside it the three files:

python
1# Folder structure
2task_manager_app/
3    models.py
4    task_manager.py
5    main.py

You can create the folder and files from the terminal:

python
1# In the terminal (these are shell commands, not Python code)
2# Windows:
3mkdir task_manager_app
4cd task_manager_app
5type nul > models.py
6type nul > task_manager.py
7type nul > main.py
8
9# macOS / Linux:
10mkdir task_manager_app
11cd task_manager_app
12touch models.py task_manager.py main.py
💡 Tip: Separating code into multiple files is a good practice. Each file has a clear responsibility: one for data, another for logic, and another for the interface. This makes the code easier to understand and maintain.

Step 2: Data Model — The Task Class

Let us start with the data model. The Task class represents an individual task with its properties.

Open the models.py file and write:

python
1from datetime import datetime
2
3
4class Task:
5    """Represents an individual task in the manager."""
6
7    def __init__(self, task_id, title, description=""):
8        self.task_id = task_id
9        self.title = title
10        self.description = description
11        self.completed = False
12        self.created_at = datetime.now().strftime("%Y-%m-%d %H:%M")
13
14    def mark_completed(self):
15        """Marks the task as completed."""
16        self.completed = True
17
18    def to_dict(self):
19        """Converts the task to a dictionary (to save as JSON)."""
20        return {
21            "task_id": self.task_id,
22            "title": self.title,
23            "description": self.description,
24            "completed": self.completed,
25            "created_at": self.created_at
26        }
27
28    @classmethod
29    def from_dict(cls, data):
30        """Creates a task from a dictionary (to load from JSON)."""
31        task = cls(data["task_id"], data["title"], data.get("description", ""))
32        task.completed = data.get("completed", False)
33        task.created_at = data.get("created_at", "")
34        return task
35
36    def __str__(self):
37        """Text representation of the task."""
38        status = "✓" if self.completed else "○"
39        text = f"[{status}] #{self.task_id} - {self.title}"
40        if self.description:
41            text += f"
42      {self.description}"
43        text += f"
44      Created: {self.created_at}"
45        return text

Let us look at what each part does:

  • __init__: Initializes the task with an ID, title, description (optional), status (pending by default), and creation date
  • mark_completed: Changes the status to completed
  • to_dict: Converts the task to a dictionary so it can be saved to a JSON file
  • from_dict: Class method that creates a task from a dictionary (to load data from JSON)
  • __str__: Defines how the task is displayed when we print it with print()

Step 3: Business Logic — The TaskManager Class

Now let us create the class that handles all operations: add, list, complete, delete, and search tasks. It also takes care of saving and loading tasks from a JSON file.

Open the task_manager.py file and write:

python
1import json
2import os
3from models import Task
4
5
6class TaskManager:
7    """Manages the task list with JSON file persistence."""
8
9    def __init__(self, filename="tasks.json"):
10        self.filename = filename
11        self.tasks = []
12        self.next_id = 1
13        self.load_tasks()
14
15    def load_tasks(self):
16        """Loads tasks from the JSON file."""
17        if not os.path.exists(self.filename):
18            return
19
20        try:
21            with open(self.filename, "r", encoding="utf-8") as file:
22                data = json.load(file)
23                self.tasks = [Task.from_dict(item) for item in data]
24                if self.tasks:
25                    self.next_id = max(t.task_id for t in self.tasks) + 1
26                print(f"Loaded {len(self.tasks)} tasks from {self.filename}")
27        except (json.JSONDecodeError, KeyError) as e:
28            print(f"Error reading task file: {e}")
29            print("Starting with an empty list.")
30            self.tasks = []
31
32    def save_tasks(self):
33        """Saves tasks to the JSON file."""
34        try:
35            data = [task.to_dict() for task in self.tasks]
36            with open(self.filename, "w", encoding="utf-8") as file:
37                json.dump(data, file, indent=2, ensure_ascii=False)
38        except IOError as e:
39            print(f"Error saving tasks: {e}")
40
41    def add_task(self, title, description=""):
42        """Adds a new task to the list."""
43        if not title or not title.strip():
44            raise ValueError("Task title cannot be empty")
45
46        task = Task(self.next_id, title.strip(), description.strip())
47        self.tasks.append(task)
48        self.next_id += 1
49        self.save_tasks()
50        return task
51
52    def list_tasks(self, show_all=True):
53        """Returns tasks (all or only pending)."""
54        if show_all:
55            return self.tasks
56        return [t for t in self.tasks if not t.completed]
57
58    def complete_task(self, task_id):
59        """Marks a task as completed."""
60        task = self._find_task(task_id)
61        if task is None:
62            raise ValueError(f"No task found with ID #{task_id}")
63        if task.completed:
64            raise ValueError(f"Task #{task_id} is already completed")
65
66        task.mark_completed()
67        self.save_tasks()
68        return task
69
70    def delete_task(self, task_id):
71        """Deletes a task from the list."""
72        task = self._find_task(task_id)
73        if task is None:
74            raise ValueError(f"No task found with ID #{task_id}")
75
76        self.tasks.remove(task)
77        self.save_tasks()
78        return task
79
80    def search_tasks(self, keyword):
81        """Searches tasks containing the keyword in title or description."""
82        if not keyword or not keyword.strip():
83            raise ValueError("Search keyword cannot be empty")
84
85        keyword = keyword.lower().strip()
86        results = [
87            t for t in self.tasks
88            if keyword in t.title.lower() or keyword in t.description.lower()
89        ]
90        return results
91
92    def get_stats(self):
93        """Returns task statistics."""
94        total = len(self.tasks)
95        completed = sum(1 for t in self.tasks if t.completed)
96        pending = total - completed
97        return {
98            "total": total,
99            "completed": completed,
100            "pending": pending
101        }
102
103    def _find_task(self, task_id):
104        """Finds a task by its ID (private method)."""
105        for task in self.tasks:
106            if task.task_id == task_id:
107                return task
108        return None

This class contains all the task manager logic:

  • load_tasks and save_tasks: Handle JSON persistence (Part 8 of the course)
  • add_task: Validates and adds a new task
  • list_tasks: Can show all or only pending tasks (list comprehensions, Part 4)
  • complete_task and delete_task: Find the task and raise errors if it does not exist (Part 9)
  • search_tasks: Searches by keyword in title and description
  • get_stats: Returns statistics using dictionaries (Part 5)
  • _find_task: Private helper method to search by ID
📌 Note: The method _find_task starts with an underscore (_). In Python, this indicates it is a "private" method — it should only be used inside the class, not from outside.

Step 4: Saving and Loading Tasks with JSON

Persistence is what ensures tasks are not lost when you close the program. Every time you add, complete, or delete a task, the program automatically saves everything to a tasks.json file.

This is what the JSON file generated by the program looks like:

python
1# Contents of tasks.json (generated automatically)
2[
3  {
4    "task_id": 1,
5    "title": "Buy milk",
6    "description": "From the corner store",
7    "completed": false,
8    "created_at": "2025-01-15 10:30"
9  },
10  {
11    "task_id": 2,
12    "title": "Study Python",
13    "description": "Finish the course final project",
14    "completed": true,
15    "created_at": "2025-01-15 10:35"
16  }
17]

The flow works like this:

  1. When the program starts, load_tasks() reads the JSON file and creates Task objects
  2. When you make any change, save_tasks() converts all tasks to dictionaries and saves them to JSON
  3. If the file does not exist (first time), the program starts with an empty list
  4. If the file is corrupted, the program shows an error and starts with an empty list instead of crashing
💡 Tip: We use ensure_ascii=False in json.dump() so that special characters (like accents) are saved correctly in the file.

Step 5: Interactive Menu — The main.py File

Finally, let us create the user interface: an interactive menu that lets the user choose what they want to do.

Open the main.py file and write:

python
1from task_manager import TaskManager
2
3
4def show_menu():
5    """Displays the main menu."""
6    print()
7    print("=" * 45)
8    print("   TASK MANAGER - Main Menu")
9    print("=" * 45)
10    print("  1. Add task")
11    print("  2. List all tasks")
12    print("  3. List pending tasks")
13    print("  4. Complete a task")
14    print("  5. Delete a task")
15    print("  6. Search tasks")
16    print("  7. View statistics")
17    print("  0. Exit")
18    print("-" * 45)
19
20
21def add_task_flow(manager):
22    """Flow for adding a task."""
23    print("
24--- Add New Task ---")
25    title = input("Title: ").strip()
26    if not title:
27        print("Error: title cannot be empty.")
28        return
29
30    description = input("Description (optional, press Enter to skip): ").strip()
31
32    try:
33        task = manager.add_task(title, description)
34        print(f"
35Task added successfully:")
36        print(task)
37    except ValueError as e:
38        print(f"Error: {e}")
39
40
41def list_tasks_flow(manager, show_all=True):
42    """Flow for listing tasks."""
43    label = "All Tasks" if show_all else "Pending Tasks"
44    print(f"
45--- {label} ---")
46
47    tasks = manager.list_tasks(show_all=show_all)
48    if not tasks:
49        print("No tasks to display.")
50        return
51
52    for task in tasks:
53        print()
54        print(task)
55    print(f"
56Total: {len(tasks)} task(s)")
57
58
59def complete_task_flow(manager):
60    """Flow for completing a task."""
61    print("
62--- Complete Task ---")
63    list_tasks_flow(manager, show_all=False)
64
65    try:
66        task_id = int(input("
67Enter the ID of the task to complete: "))
68        task = manager.complete_task(task_id)
69        print(f"
70Task completed:")
71        print(task)
72    except ValueError as e:
73        print(f"Error: {e}")
74
75
76def delete_task_flow(manager):
77    """Flow for deleting a task."""
78    print("
79--- Delete Task ---")
80    list_tasks_flow(manager)
81
82    try:
83        task_id = int(input("
84Enter the ID of the task to delete: "))
85        confirm = input(f"Are you sure you want to delete task #{task_id}? (y/n): ")
86        if confirm.lower() == "y":
87            task = manager.delete_task(task_id)
88            print(f"
89Task deleted: {task.title}")
90        else:
91            print("Operation cancelled.")
92    except ValueError as e:
93        print(f"Error: {e}")
94
95
96def search_tasks_flow(manager):
97    """Flow for searching tasks."""
98    print("
99--- Search Tasks ---")
100    keyword = input("Search keyword: ").strip()
101
102    try:
103        results = manager.search_tasks(keyword)
104        if not results:
105            print(f"No tasks found with '{keyword}'.")
106            return
107
108        print(f"
109Results for '{keyword}': {len(results)} task(s)")
110        for task in results:
111            print()
112            print(task)
113    except ValueError as e:
114        print(f"Error: {e}")
115
116
117def stats_flow(manager):
118    """Flow for displaying statistics."""
119    print("
120--- Statistics ---")
121    stats = manager.get_stats()
122
123    print(f"  Total tasks:  {stats['total']}")
124    print(f"  Completed:    {stats['completed']}")
125    print(f"  Pending:      {stats['pending']}")
126
127    if stats["total"] > 0:
128        percentage = (stats["completed"] / stats["total"]) * 100
129        bar_length = 20
130        filled = int(bar_length * stats["completed"] / stats["total"])
131        bar = "█" * filled + "░" * (bar_length - filled)
132        print(f"  Progress:     [{bar}] {percentage:.0f}%")
133
134
135def main():
136    """Main function of the program."""
137    print("
138Welcome to the Task Manager")
139    manager = TaskManager()
140
141    while True:
142        show_menu()
143        option = input("Choose an option: ").strip()
144
145        if option == "1":
146            add_task_flow(manager)
147        elif option == "2":
148            list_tasks_flow(manager, show_all=True)
149        elif option == "3":
150            list_tasks_flow(manager, show_all=False)
151        elif option == "4":
152            complete_task_flow(manager)
153        elif option == "5":
154            delete_task_flow(manager)
155        elif option == "6":
156            search_tasks_flow(manager)
157        elif option == "7":
158            stats_flow(manager)
159        elif option == "0":
160            print("
161Goodbye! Your tasks have been saved.")
162            break
163        else:
164            print("Invalid option. Choose a number from 0 to 7.")
165
166
167if __name__ == "__main__":
168    main()

To run the program, open a terminal in the project folder and type:

python
1# Run the task manager
2python main.py

Step 6: Error Handling Throughout the Project

Notice how error handling is integrated throughout the entire project:

In the model (models.py)

  • The from_dict method uses .get() with default values to avoid KeyError

In the logic (task_manager.py)

  • load_tasks: Catches json.JSONDecodeError if the file is corrupted
  • save_tasks: Catches IOError if the file cannot be written
  • add_task: Validates that the title is not empty
  • complete_task: Verifies the task exists and is not already completed
  • delete_task: Verifies the task exists before deleting
  • search_tasks: Validates that the search keyword is not empty

In the interface (main.py)

  • Each flow uses try/except to catch validation errors and show friendly messages
  • The delete_task_flow function asks for confirmation before deleting
  • The main menu handles invalid options with a clear message
python
1# Example of how errors look to the user:
2
3# If they try to complete a task that does not exist:
4# "Error: No task found with ID #99"
5
6# If they try to add a task without a title:
7# "Error: title cannot be empty."
8
9# If they type letters where a number is expected:
10# "Error: invalid literal for int() with base 10: 'abc'"
⚠️ Important: Always validate user data before processing it. Never trust that the user will enter correct data — there can always be errors, whether accidental or intentional.

Complete Project Code

Here is the complete code for each file so you can copy and run it directly:

File: models.py

python
1from datetime import datetime
2
3
4class Task:
5    """Represents an individual task in the manager."""
6
7    def __init__(self, task_id, title, description=""):
8        self.task_id = task_id
9        self.title = title
10        self.description = description
11        self.completed = False
12        self.created_at = datetime.now().strftime("%Y-%m-%d %H:%M")
13
14    def mark_completed(self):
15        """Marks the task as completed."""
16        self.completed = True
17
18    def to_dict(self):
19        """Converts the task to a dictionary (to save as JSON)."""
20        return {
21            "task_id": self.task_id,
22            "title": self.title,
23            "description": self.description,
24            "completed": self.completed,
25            "created_at": self.created_at
26        }
27
28    @classmethod
29    def from_dict(cls, data):
30        """Creates a task from a dictionary (to load from JSON)."""
31        task = cls(data["task_id"], data["title"], data.get("description", ""))
32        task.completed = data.get("completed", False)
33        task.created_at = data.get("created_at", "")
34        return task
35
36    def __str__(self):
37        """Text representation of the task."""
38        status = "✓" if self.completed else "○"
39        text = f"[{status}] #{self.task_id} - {self.title}"
40        if self.description:
41            text += f"\n      {self.description}"
42        text += f"\n      Created: {self.created_at}"
43        return text

File: task_manager.py

python
1import json
2import os
3from models import Task
4
5
6class TaskManager:
7    """Manages the task list with JSON file persistence."""
8
9    def __init__(self, filename="tasks.json"):
10        self.filename = filename
11        self.tasks = []
12        self.next_id = 1
13        self.load_tasks()
14
15    def load_tasks(self):
16        """Loads tasks from the JSON file."""
17        if not os.path.exists(self.filename):
18            return
19
20        try:
21            with open(self.filename, "r", encoding="utf-8") as file:
22                data = json.load(file)
23                self.tasks = [Task.from_dict(item) for item in data]
24                if self.tasks:
25                    self.next_id = max(t.task_id for t in self.tasks) + 1
26                print(f"Loaded {len(self.tasks)} tasks from {self.filename}")
27        except (json.JSONDecodeError, KeyError) as e:
28            print(f"Error reading task file: {e}")
29            print("Starting with an empty list.")
30            self.tasks = []
31
32    def save_tasks(self):
33        """Saves tasks to the JSON file."""
34        try:
35            data = [task.to_dict() for task in self.tasks]
36            with open(self.filename, "w", encoding="utf-8") as file:
37                json.dump(data, file, indent=2, ensure_ascii=False)
38        except IOError as e:
39            print(f"Error saving tasks: {e}")
40
41    def add_task(self, title, description=""):
42        """Adds a new task to the list."""
43        if not title or not title.strip():
44            raise ValueError("Task title cannot be empty")
45
46        task = Task(self.next_id, title.strip(), description.strip())
47        self.tasks.append(task)
48        self.next_id += 1
49        self.save_tasks()
50        return task
51
52    def list_tasks(self, show_all=True):
53        """Returns tasks (all or only pending)."""
54        if show_all:
55            return self.tasks
56        return [t for t in self.tasks if not t.completed]
57
58    def complete_task(self, task_id):
59        """Marks a task as completed."""
60        task = self._find_task(task_id)
61        if task is None:
62            raise ValueError(f"No task found with ID #{task_id}")
63        if task.completed:
64            raise ValueError(f"Task #{task_id} is already completed")
65
66        task.mark_completed()
67        self.save_tasks()
68        return task
69
70    def delete_task(self, task_id):
71        """Deletes a task from the list."""
72        task = self._find_task(task_id)
73        if task is None:
74            raise ValueError(f"No task found with ID #{task_id}")
75
76        self.tasks.remove(task)
77        self.save_tasks()
78        return task
79
80    def search_tasks(self, keyword):
81        """Searches tasks containing the keyword."""
82        if not keyword or not keyword.strip():
83            raise ValueError("Search keyword cannot be empty")
84
85        keyword = keyword.lower().strip()
86        results = [
87            t for t in self.tasks
88            if keyword in t.title.lower() or keyword in t.description.lower()
89        ]
90        return results
91
92    def get_stats(self):
93        """Returns task statistics."""
94        total = len(self.tasks)
95        completed = sum(1 for t in self.tasks if t.completed)
96        pending = total - completed
97        return {"total": total, "completed": completed, "pending": pending}
98
99    def _find_task(self, task_id):
100        """Finds a task by its ID (private method)."""
101        for task in self.tasks:
102            if task.task_id == task_id:
103                return task
104        return None

File: main.py

python
1from task_manager import TaskManager
2
3
4def show_menu():
5    """Displays the main menu."""
6    print()
7    print("=" * 45)
8    print("   TASK MANAGER - Main Menu")
9    print("=" * 45)
10    print("  1. Add task")
11    print("  2. List all tasks")
12    print("  3. List pending tasks")
13    print("  4. Complete a task")
14    print("  5. Delete a task")
15    print("  6. Search tasks")
16    print("  7. View statistics")
17    print("  0. Exit")
18    print("-" * 45)
19
20
21def add_task_flow(manager):
22    """Flow for adding a task."""
23    print("\n--- Add New Task ---")
24    title = input("Title: ").strip()
25    if not title:
26        print("Error: title cannot be empty.")
27        return
28
29    description = input("Description (optional, press Enter to skip): ").strip()
30
31    try:
32        task = manager.add_task(title, description)
33        print(f"\nTask added successfully:")
34        print(task)
35    except ValueError as e:
36        print(f"Error: {e}")
37
38
39def list_tasks_flow(manager, show_all=True):
40    """Flow for listing tasks."""
41    label = "All Tasks" if show_all else "Pending Tasks"
42    print(f"\n--- {label} ---")
43
44    tasks = manager.list_tasks(show_all=show_all)
45    if not tasks:
46        print("No tasks to display.")
47        return
48
49    for task in tasks:
50        print()
51        print(task)
52    print(f"\nTotal: {len(tasks)} task(s)")
53
54
55def complete_task_flow(manager):
56    """Flow for completing a task."""
57    print("\n--- Complete Task ---")
58    list_tasks_flow(manager, show_all=False)
59
60    try:
61        task_id = int(input("\nEnter the ID of the task to complete: "))
62        task = manager.complete_task(task_id)
63        print(f"\nTask completed:")
64        print(task)
65    except ValueError as e:
66        print(f"Error: {e}")
67
68
69def delete_task_flow(manager):
70    """Flow for deleting a task."""
71    print("\n--- Delete Task ---")
72    list_tasks_flow(manager)
73
74    try:
75        task_id = int(input("\nEnter the ID of the task to delete: "))
76        confirm = input(f"Are you sure you want to delete task #{task_id}? (y/n): ")
77        if confirm.lower() == "y":
78            task = manager.delete_task(task_id)
79            print(f"\nTask deleted: {task.title}")
80        else:
81            print("Operation cancelled.")
82    except ValueError as e:
83        print(f"Error: {e}")
84
85
86def search_tasks_flow(manager):
87    """Flow for searching tasks."""
88    print("\n--- Search Tasks ---")
89    keyword = input("Search keyword: ").strip()
90
91    try:
92        results = manager.search_tasks(keyword)
93        if not results:
94            print(f"No tasks found with '{keyword}'.")
95            return
96
97        print(f"\nResults for '{keyword}': {len(results)} task(s)")
98        for task in results:
99            print()
100            print(task)
101    except ValueError as e:
102        print(f"Error: {e}")
103
104
105def stats_flow(manager):
106    """Flow for displaying statistics."""
107    print("\n--- Statistics ---")
108    stats = manager.get_stats()
109
110    print(f"  Total tasks:  {stats['total']}")
111    print(f"  Completed:    {stats['completed']}")
112    print(f"  Pending:      {stats['pending']}")
113
114    if stats["total"] > 0:
115        percentage = (stats["completed"] / stats["total"]) * 100
116        bar_length = 20
117        filled = int(bar_length * stats["completed"] / stats["total"])
118        bar = "█" * filled + "░" * (bar_length - filled)
119        print(f"  Progress:     [{bar}] {percentage:.0f}%")
120
121
122def main():
123    """Main function of the program."""
124    print("\nWelcome to the Task Manager")
125    manager = TaskManager()
126
127    while True:
128        show_menu()
129        option = input("Choose an option: ").strip()
130
131        if option == "1":
132            add_task_flow(manager)
133        elif option == "2":
134            list_tasks_flow(manager, show_all=True)
135        elif option == "3":
136            list_tasks_flow(manager, show_all=False)
137        elif option == "4":
138            complete_task_flow(manager)
139        elif option == "5":
140            delete_task_flow(manager)
141        elif option == "6":
142            search_tasks_flow(manager)
143        elif option == "7":
144            stats_flow(manager)
145        elif option == "0":
146            print("\nGoodbye! Your tasks have been saved.")
147            break
148        else:
149            print("Invalid option. Choose a number from 0 to 7.")
150
151
152if __name__ == "__main__":
153    main()

Ideas to Improve the Project

You already have a working task manager. Here are some ideas to keep practicing and improve the project:

Easy level

  • Terminal colors: Install the colorama library (pip install colorama) and add colors to the menu and messages. For example, completed tasks in green and pending ones in yellow.
  • Sort tasks: Add an option to sort tasks by creation date, by title (alphabetically), or by status.
  • Edit tasks: Add the ability to change the title or description of an existing task.

Intermediate level

  • Priorities: Add a priority field (high, medium, low) to tasks and allow filtering by priority.
  • Due dates: Add a due date to tasks and show alerts when a task is about to expire.
  • Categories: Allow assigning categories to tasks (work, personal, study) and filtering by category.

Advanced level

  • SQLite database: Instead of JSON, use SQLite to store tasks. Python includes the sqlite3 module without needing to install anything.
  • Graphical interface: Create a version with a graphical interface using tkinter (comes included with Python).
  • REST API: Convert the manager into a web API using Flask or FastAPI — so you can access your tasks from a browser.
💡 Tip: The best way to learn programming is by building projects. Do not limit yourself to following tutorials — modify this project, break things, fix them. Every error you solve makes you a better programmer.

Course Conclusion

Congratulations! You have completed the Python from Scratch Course. Throughout 10 articles, you have gone from knowing nothing about programming to building a complete project with multiple files, classes, data persistence, and error handling.

Let us review everything you learned:

Article Topic
Part 1 Installing Python and your first program
Part 2 Variables and data types
Part 3 Conditionals (if, elif, else)
Part 4 Loops (for, while) and lists
Part 5 Functions and dictionaries
Part 6 Strings and text methods
Part 7 Object-oriented programming (OOP)
Part 8 Files and modules
Part 9 Error handling and exceptions
Part 10 Final project: task manager

What comes next after this course?

Now that you have mastered the fundamentals of Python, you have many options to keep growing:

  • Web Development: Learn Flask or Django to create web applications with Python. Flask is simpler to start with, Django is more complete for large projects.
  • Data Science: Learn pandas, NumPy, and Matplotlib to analyze and visualize data. It is one of the best-paid areas in tech.
  • Automation: Use Python to automate repetitive tasks: rename files, extract data from web pages (web scraping with BeautifulSoup), send automatic emails, etc.
  • REST APIs: Learn FastAPI to create modern, fast APIs. It is the most popular Python framework for APIs.
  • Machine Learning: Learn scikit-learn and TensorFlow to create artificial intelligence models.
  • Databases: Learn SQL and how to connect Python with databases like PostgreSQL or MySQL.
💡 Final advice: Programming is learned by programming. Do not try to learn everything at once. Choose an area that interests you, build a project, and learn as you go. Every project you complete will bring you closer to becoming a professional developer. Keep coding and never stop learning!
Share:
CV

Cristhian Villegas

Software Engineer specializing in Java, Spring Boot, Angular & AWS. Building scalable distributed systems with clean architecture.

Comments

Sign in to leave a comment

No comments yet. Be the first!

Related Articles