PYTHON OOP · 2026

Python Data Structures & OOP

A complete object-oriented data structure for task management. Implements encapsulation, inheritance, composition, and type-safe enums. Clean, professional Python patterns with full code examples.

⏱ 15 min read 📅 Mar 2026 🎓 Intermediate 🖥️ OOP

Advertisement

5 classes 3 enums dataclass uuid type hints property decorators

01 — OOP FOUNDATIONS

Building a Task Manager with Python

A complete object-oriented data structure for task management. Implements encapsulation, inheritance, composition, and type-safe enums. Midnight blue and obsidian theme.

Advertisement

02 — CORE ENUMS

Priority & Task Status

from enum import Enum class Priority(Enum): LOW = 1 MEDIUM = 2 HIGH = 3 CRITICAL = 4 class TaskStatus(Enum): PENDING = "pending" IN_PROGRESS = "in_progress" COMPLETED = "completed" ARCHIVED = "archived"

03 — DATA CLASS · COMMENT

Comment with Dataclass

from dataclasses import dataclass from datetime import datetime import uuid @dataclass class Comment: author: str content: str timestamp: datetime comment_id: str = None def __post_init__(self): if self.comment_id is None: self.comment_id = str(uuid.uuid4())[:8]

04 — TASK CLASS

Core Task Implementation

class Task: def __init__(self, title: str, description: str = "", priority: Priority = Priority.MEDIUM): self.id = str(uuid.uuid4())[:8] self.title = title self.description = description self.priority = priority self.status = TaskStatus.PENDING self.created_at = datetime.now() self.updated_at = datetime.now() self.completed_at = None self.tags = set() self.comments = [] self.assigned_to = None self.estimated_hours = None def update_status(self, status: TaskStatus): self.status = status self.updated_at = datetime.now() if status == TaskStatus.COMPLETED: self.completed_at = datetime.now() def add_tag(self, tag: str): self.tags.add(tag.lower()) self.updated_at = datetime.now() def add_comment(self, author: str, content: str): self.comments.append(Comment(author, content, datetime.now())) def assign_to(self, user_id: str): self.assigned_to = user_id self.updated_at = datetime.now() @property def is_overdue(self) -> bool: if self.status == TaskStatus.COMPLETED: return False if hasattr(self, 'due_date') and self.due_date: return datetime.now() > self.due_date return False def __str__(self): symbols = {TaskStatus.COMPLETED: '✅', TaskStatus.IN_PROGRESS: '⚡', TaskStatus.PENDING: '⏳'} symbol = symbols.get(self.status, '📌') return f"{symbol} [{self.priority.name}] {self.title}"

05 — PROJECT CLASS

Task Container with Composition

class Project: def __init__(self, name: str, description: str = ""): self.id = str(uuid.uuid4())[:8] self.name = name self.description = description self.tasks = {} self.created_at = datetime.now() self.updated_at = datetime.now() self.owner = None self.members = set() def add_task(self, task: Task) -> str: self.tasks[task.id] = task self.updated_at = datetime.now() return task.id def get_tasks_by_priority(self, priority: Priority): return [t for t in self.tasks.values() if t.priority == priority] def get_tasks_by_status(self, status: TaskStatus): return [t for t in self.tasks.values() if t.status == status] def get_tasks_by_tag(self, tag: str): tag = tag.lower() return [t for t in self.tasks.values() if tag in t.tags] def add_member(self, user_id: str): self.members.add(user_id) @property def progress(self): total = len(self.tasks) if total == 0: return {'percentage': 0} completed = len(self.get_tasks_by_status(TaskStatus.COMPLETED)) return {'completed': completed, 'percentage': (completed/total)*100} def __str__(self): return f"📁 {self.name} ({len(self.tasks)} tasks) - {self.progress['percentage']:.1f}% complete"

06 — USER CLASS

User with Project Ownership

class User: def __init__(self, username: str, email: str, full_name: str = ""): self.id = str(uuid.uuid4())[:8] self.username = username self.email = email self.full_name = full_name or username self.created_at = datetime.now() self.last_active = datetime.now() self.projects = {} self.notifications = [] def create_project(self, name: str, description: str = "") -> Project: project = Project(name, description) project.owner = self.id project.add_member(self.id) self.projects[project.id] = project return project def join_project(self, project: Project): self.projects[project.id] = project project.add_member(self.id) self.last_active = datetime.now() @property def is_active(self) -> bool: return (datetime.now() - self.last_active).total_seconds() < 300 def __str__(self): status = "🟢" if self.is_active else "⚪" return f"{status} {self.full_name} (@{self.username})"

07 — TASK MANAGER (FACADE)

Orchestration Layer

class TaskManager: def __init__(self, name: str = "Task Manager"): self.name = name self.users = {} self.projects = {} self.tasks = {} self.activity_log = [] def create_user(self, username: str, email: str, full_name: str = "") -> User: if username in [u.username for u in self.users.values()]: raise ValueError(f"User {username} exists") user = User(username, email, full_name) self.users[user.id] = user self._log(f"User created: {username}") return user def register_project(self, project: Project): self.projects[project.id] = project for task in project.tasks.values(): self.tasks[task.id] = task self._log(f"Project registered: {project.name}") def search_tasks(self, query: str): query = query.lower() return [t for t in self.tasks.values() if query in t.title.lower() or query in [tag for tag in t.tags]] def get_statistics(self): total_tasks = len(self.tasks) completed = len([t for t in self.tasks.values() if t.status == TaskStatus.COMPLETED]) active_users = len([u for u in self.users.values() if u.is_active]) return { 'total_users': len(self.users), 'active_users': active_users, 'total_projects': len(self.projects), 'total_tasks': total_tasks, 'completed_tasks': completed, 'completion_rate': (completed/total_tasks*100) if total_tasks else 0 } def _log(self, message: str): self.activity_log.append(f"[{datetime.now().strftime('%H:%M')}] {message}") def __str__(self): s = self.get_statistics() return f"{self.name} · {s['total_users']} users · {s['total_projects']} projects · {s['total_tasks']} tasks"

08 — EXAMPLE USAGE

Putting It All Together

INSTANTIATION

manager = TaskManager("OBSIDIAN")
alice = manager.create_user("alice", "[email protected]", "Alice Johnson")
bob = manager.create_user("bob", "[email protected]", "Bob Smith")
web = alice.create_project("Web Redesign")
task1 = Task("fix auth", priority=Priority.CRITICAL)
task1.add_tag("security")
task1.assign_to(bob.id)
web.add_task(task1)
manager.register_project(web)

OPERATIONS

web.get_tasks_by_priority(Priority.HIGH)
web.get_tasks_by_tag("security")
task1.update_status(TaskStatus.IN_PROGRESS)
task1.add_comment("bob", "started debugging")
print(web.progress)
manager.search_tasks("auth")

OUTPUT

>>> print(manager)
OBSIDIAN · 2 users · 1 projects · 3 tasks

>>> print(alice)
🟢 Alice Johnson (@alice)

>>> print(web)
📁 Web Redesign (3 tasks) - 33.3% complete

>>> for t in web.get_tasks_by_priority(Priority.CRITICAL): print(t)
✅ [CRITICAL] fix auth

>>> manager.get_statistics()
{'total_users': 2, 'active_users': 2, 'total_tasks': 3, 'completion_rate': 33.3}

09 — OOP CONCEPTS COVERED

Encapsulation, Inheritance, Composition

encapsulation inheritance (Enum) composition dataclass property decorator type hints uuid identifiers magic __str__ factory methods set/dict collections

TASK LIFECYCLE

  • Task() → PENDING
  • update_status(IN_PROGRESS)
  • add_comment() / add_tag()
  • assign_to(user)
  • update_status(COMPLETED)
  • auto timestamp & history

MANAGER QUERIES

  • search_tasks("keyword")
  • get_tasks_by_priority()
  • get_tasks_by_tag()
  • get_assigned_tasks()
  • progress / statistics
  • activity log

Advertisement

FAQ

Frequently Asked Questions

Inheritance creates an 'is-a' relationship where a subclass extends a parent class. Composition creates a 'has-a' relationship by including instances of other classes. Composition offers more flexibility and looser coupling, making it preferable over deep inheritance hierarchies.

Use dataclasses when you need classes that primarily store data with minimal behavior. They automatically generate __init__, __repr__, __eq__, and other special methods, reducing boilerplate. Perfect for DTOs, value objects, and configuration containers.

__repr__ aims to be unambiguous and is used for debugging, ideally showing how to recreate the object. __str__ is for readable display to end-users. When only __repr__ is defined, it serves as a fallback for __str__.

Click a platform above to generate an AI-crafted caption tailored for that network.

COMMUNITY

Comments

0 comments

Be the first to leave a comment! 👋

Stay in the Loop

Get new Python guides, OOP deep-dives, and code insights delivered to your inbox.

Join readers learning Python & AI. Unsubscribe anytime.