Bài 16: Python Basics - Practices & Projects

Mục Tiêu Bài Học

Sau khi hoàn thành bài này, bạn sẽ:

  • ✅ Tổng hợp tất cả kiến thức Python cơ bản
  • ✅ Xây dựng các ứng dụng thực tế hoàn chỉnh
  • ✅ Áp dụng OOP, file I/O, error handling
  • ✅ Viết code có cấu trúc và maintainable
  • ✅ Tự tin giải quyết bài toán thực tế

Tổng Quan

Module Python Cơ Bản đã hoàn thành với 15 bài học:

  1. ✅ Giới thiệu Python
  2. ✅ Variables & Data Types
  3. ✅ Operators
  4. ✅ Strings
  5. ✅ Lists
  6. ✅ Tuples
  7. ✅ Dictionaries
  8. ✅ Sets
  9. ✅ Control Flow
  10. ✅ Loops
  11. ✅ Functions
  12. ✅ Modules & Packages
  13. ✅ File I/O
  14. ✅ Error Handling
  15. ✅ OOP

Bây giờ là lúc practice với các dự án thực tế!

Bài Tập Lớn

Project 1: Contact Management System 📇

Mô tả: Xây dựng ứng dụng quản lý danh bạ với CLI interface.

Yêu cầu chức năng:

  • Thêm, sửa, xóa, tìm kiếm contact
  • Lưu trữ: name, phone, email, address, birthday
  • Xuất/nhập data từ JSON file
  • Validation (email format, phone number)
  • List contacts với sorting và filtering
  • Backup và restore data

Kiến thức sử dụng:

  • OOP (Contact, ContactBook classes)
  • File I/O (JSON)
  • Error handling
  • Data validation
  • List operations
  • Dictionaries

Hướng dẫn thực hiện:

Bước 1: Thiết kế classes

# contact.pyimport jsonimport refrom datetime import datetime class Contact:    """Represents a single contact."""        def __init__(self, name, phone, email="", address="", birthday=""):        self.name = name        self.phone = phone        self.email = email        self.address = address        self.birthday = birthday        self.created_at = datetime.now().isoformat()        @staticmethod    def validate_email(email):        """Validate email format."""        if not email:            return True  # Email is optional        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'        return re.match(pattern, email) is not None        @staticmethod    def validate_phone(phone):        """Validate phone number (10 digits)."""        return phone.isdigit() and len(phone) == 10        def to_dict(self):        """Convert to dictionary."""        return {            'name': self.name,            'phone': self.phone,            'email': self.email,            'address': self.address,            'birthday': self.birthday,            'created_at': self.created_at        }        @classmethod    def from_dict(cls, data):        """Create contact from dictionary."""        contact = cls(            data['name'],            data['phone'],            data.get('email', ''),            data.get('address', ''),            data.get('birthday', '')        )        contact.created_at = data.get('created_at', datetime.now().isoformat())        return contact        def __str__(self):        return f"{self.name} - {self.phone}"        def __repr__(self):        return f"Contact('{self.name}', '{self.phone}')" class ContactBook:    """Manages collection of contacts."""        def __init__(self, filename='contacts.json'):        self.filename = filename        self.contacts = []        self.load()        def add_contact(self, contact):        """Add new contact."""        # Check duplicate phone        if self.find_by_phone(contact.phone):            raise ValueError("Phone number already exists")                # Validate        if not Contact.validate_phone(contact.phone):            raise ValueError("Invalid phone number")                if contact.email and not Contact.validate_email(contact.email):            raise ValueError("Invalid email format")                self.contacts.append(contact)        self.save()        return True        def remove_contact(self, phone):        """Remove contact by phone."""        contact = self.find_by_phone(phone)        if contact:            self.contacts.remove(contact)            self.save()            return True        return False        def update_contact(self, phone, **kwargs):        """Update contact information."""        contact = self.find_by_phone(phone)        if not contact:            return False                for key, value in kwargs.items():            if hasattr(contact, key):                setattr(contact, key, value)                self.save()        return True        def find_by_phone(self, phone):        """Find contact by phone number."""        for contact in self.contacts:            if contact.phone == phone:                return contact        return None        def search(self, query):        """Search contacts by name, phone, or email."""        query = query.lower()        results = []        for contact in self.contacts:            if (query in contact.name.lower() or                query in contact.phone or                query in contact.email.lower()):                results.append(contact)        return results        def list_all(self, sort_by='name'):        """List all contacts sorted."""        if sort_by == 'name':            return sorted(self.contacts, key=lambda c: c.name)        elif sort_by == 'phone':            return sorted(self.contacts, key=lambda c: c.phone)        return self.contacts        def save(self):        """Save contacts to JSON file."""        try:            data = [contact.to_dict() for contact in self.contacts]            with open(self.filename, 'w', encoding='utf-8') as f:                json.dump(data, f, indent=2, ensure_ascii=False)        except Exception as e:            print(f"Error saving: {e}")        def load(self):        """Load contacts from JSON file."""        try:            with open(self.filename, 'r', encoding='utf-8') as f:                data = json.load(f)                self.contacts = [Contact.from_dict(item) for item in data]        except FileNotFoundError:            self.contacts = []        except Exception as e:            print(f"Error loading: {e}")            self.contacts = []        def backup(self, backup_file):        """Create backup."""        import shutil        try:            shutil.copy(self.filename, backup_file)            return True        except Exception as e:            print(f"Backup failed: {e}")            return False        def __len__(self):        return len(self.contacts)

Bước 2: CLI Interface

# main.pydef display_menu():    """Display main menu."""    print("\n" + "="*50)    print("📇 CONTACT MANAGEMENT SYSTEM")    print("="*50)    print("1. Add Contact")    print("2. View All Contacts")    print("3. Search Contact")    print("4. Update Contact")    print("5. Delete Contact")    print("6. Backup Data")    print("7. Statistics")    print("0. Exit")    print("="*50) def add_contact_interactive(book):    """Interactive add contact."""    print("\n--- Add New Contact ---")    try:        name = input("Name: ").strip()        phone = input("Phone (10 digits): ").strip()        email = input("Email (optional): ").strip()        address = input("Address (optional): ").strip()        birthday = input("Birthday (DD/MM/YYYY, optional): ").strip()                contact = Contact(name, phone, email, address, birthday)        book.add_contact(contact)        print(f"✅ Contact '{name}' added successfully!")    except ValueError as e:        print(f"❌ Error: {e}")    except Exception as e:        print(f"❌ Unexpected error: {e}") def view_all_contacts(book):    """View all contacts."""    contacts = book.list_all()    if not contacts:        print("\n📭 No contacts found.")        return        print(f"\n--- All Contacts ({len(contacts)}) ---")    for i, contact in enumerate(contacts, 1):        print(f"{i}. {contact.name}")        print(f"   📞 {contact.phone}")        if contact.email:            print(f"   📧 {contact.email}")        if contact.address:            print(f"   🏠 {contact.address}")        if contact.birthday:            print(f"   🎂 {contact.birthday}")        print() def search_contact_interactive(book):    """Interactive search."""    query = input("\nEnter search query: ").strip()    results = book.search(query)        if not results:        print("❌ No contacts found.")        return        print(f"\n--- Search Results ({len(results)}) ---")    for contact in results:        print(f"• {contact.name} - {contact.phone}")        if contact.email:            print(f"  📧 {contact.email}") def main():    """Main application loop."""    book = ContactBook()        while True:        display_menu()        choice = input("\nEnter choice: ").strip()                if choice == '1':            add_contact_interactive(book)        elif choice == '2':            view_all_contacts(book)        elif choice == '3':            search_contact_interactive(book)        elif choice == '4':            phone = input("\nEnter phone to update: ").strip()            contact = book.find_by_phone(phone)            if contact:                print(f"Updating: {contact.name}")                name = input(f"New name [{contact.name}]: ").strip() or contact.name                email = input(f"New email [{contact.email}]: ").strip() or contact.email                book.update_contact(phone, name=name, email=email)                print("✅ Updated successfully!")            else:                print("❌ Contact not found.")        elif choice == '5':            phone = input("\nEnter phone to delete: ").strip()            if book.remove_contact(phone):                print("✅ Contact deleted.")            else:                print("❌ Contact not found.")        elif choice == '6':            backup_file = f"contacts_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"            if book.backup(backup_file):                print(f"✅ Backup created: {backup_file}")        elif choice == '7':            print(f"\n📊 Statistics:")            print(f"Total contacts: {len(book)}")            with_email = sum(1 for c in book.contacts if c.email)            print(f"With email: {with_email}")        elif choice == '0':            print("\n👋 Goodbye!")            break        else:            print("❌ Invalid choice!") if __name__ == "__main__":    main()

Bước 3: Testing

# test_contact.pydef test_contact_validation():    """Test validation."""    print("Testing validation...")        # Valid email    assert Contact.validate_email("[email protected]") == True    assert Contact.validate_email("invalid-email") == False        # Valid phone    assert Contact.validate_phone("0123456789") == True    assert Contact.validate_phone("123") == False        print("✅ All validation tests passed!") def test_contact_book():    """Test contact book operations."""    print("\nTesting ContactBook...")        book = ContactBook('test_contacts.json')        # Add contact    contact = Contact("Test User", "0123456789", "[email protected]")    book.add_contact(contact)    assert len(book) == 1        # Find contact    found = book.find_by_phone("0123456789")    assert found is not None    assert found.name == "Test User"        # Search    results = book.search("test")    assert len(results) > 0        # Remove    book.remove_contact("0123456789")    assert len(book) == 0        print("✅ All ContactBook tests passed!") if __name__ == "__main__":    test_contact_validation()    test_contact_book()

Mở rộng thêm:

  • Import/export CSV format
  • Birthday reminders (upcoming birthdays)
  • Groups/categories cho contacts
  • Photo cho mỗi contact
  • Export to VCF (vCard format)

Project 2: Personal Finance Tracker 💰

Mô tả: Ứng dụng quản lý thu chi cá nhân.

Yêu cầu chức năng:

  • Thêm giao dịch (thu/chi)
  • Phân loại (food, transport, entertainment, etc.)
  • Xem báo cáo theo tháng/năm
  • Thống kê theo category
  • Budget planning và warnings
  • Export reports (JSON, CSV)

Kiến thức sử dụng:

  • OOP (Transaction, Account classes)
  • Datetime handling
  • File I/O
  • Data aggregation
  • List comprehensions
  • Dictionaries và defaultdict

Hướng dẫn thực hiện:

Bước 1: Transaction Class

# finance.pyfrom datetime import datetimefrom collections import defaultdictimport json class Transaction:    """Represents a financial transaction."""        CATEGORIES = [        'food', 'transport', 'entertainment', 'shopping',        'bills', 'healthcare', 'education', 'salary', 'other'    ]        def __init__(self, amount, category, description, trans_type='expense', date=None):        """        Initialize transaction.                Args:            amount: Transaction amount            category: Category name            description: Transaction description            trans_type: 'income' or 'expense'            date: Transaction date (default: today)        """        self.amount = float(amount)        self.category = category.lower()        self.description = description        self.trans_type = trans_type        self.date = date or datetime.now()                if self.category not in self.CATEGORIES:            raise ValueError(f"Invalid category. Choose from: {', '.join(self.CATEGORIES)}")                if self.trans_type not in ['income', 'expense']:            raise ValueError("Transaction type must be 'income' or 'expense'")        def to_dict(self):        """Convert to dictionary."""        return {            'amount': self.amount,            'category': self.category,            'description': self.description,            'trans_type': self.trans_type,            'date': self.date.isoformat()        }        @classmethod    def from_dict(cls, data):        """Create transaction from dictionary."""        return cls(            data['amount'],            data['category'],            data['description'],            data['trans_type'],            datetime.fromisoformat(data['date'])        )        def __str__(self):        sign = '+' if self.trans_type == 'income' else '-'        return f"{sign}${self.amount:.2f} - {self.category} - {self.description}" class FinanceTracker:    """Manages financial transactions."""        def __init__(self, filename='transactions.json'):        self.filename = filename        self.transactions = []        self.budgets = {}  # category: amount        self.load()        def add_transaction(self, transaction):        """Add new transaction."""        self.transactions.append(transaction)        self.save()                # Check budget warning        if transaction.trans_type == 'expense':            self._check_budget_warning(transaction.category)        def get_balance(self):        """Calculate current balance."""        income = sum(t.amount for t in self.transactions if t.trans_type == 'income')        expense = sum(t.amount for t in self.transactions if t.trans_type == 'expense')        return income - expense        def get_transactions_by_month(self, year, month):        """Get transactions for specific month."""        return [            t for t in self.transactions            if t.date.year == year and t.date.month == month        ]        def get_monthly_summary(self, year, month):        """Get monthly income/expense summary."""        transactions = self.get_transactions_by_month(year, month)                income = sum(t.amount for t in transactions if t.trans_type == 'income')        expense = sum(t.amount for t in transactions if t.trans_type == 'expense')                # Category breakdown        category_expense = defaultdict(float)        for t in transactions:            if t.trans_type == 'expense':                category_expense[t.category] += t.amount                return {            'income': income,            'expense': expense,            'balance': income - expense,            'by_category': dict(category_expense),            'transaction_count': len(transactions)        }        def set_budget(self, category, amount):        """Set budget for category."""        self.budgets[category] = float(amount)        self.save()        def _check_budget_warning(self, category):        """Check if category spending exceeds budget."""        if category not in self.budgets:            return                # Get current month spending        now = datetime.now()        month_transactions = self.get_transactions_by_month(now.year, now.month)                category_total = sum(            t.amount for t in month_transactions            if t.trans_type == 'expense' and t.category == category        )                budget = self.budgets[category]        if category_total > budget:            print(f"⚠️  WARNING: {category} budget exceeded!")            print(f"   Budget: ${budget:.2f}, Spent: ${category_total:.2f}")        def get_category_spending(self, category, start_date=None, end_date=None):        """Get total spending for category in date range."""        transactions = self.transactions                if start_date:            transactions = [t for t in transactions if t.date >= start_date]        if end_date:            transactions = [t for t in transactions if t.date <= end_date]                return sum(            t.amount for t in transactions            if t.trans_type == 'expense' and t.category == category        )        def save(self):        """Save to JSON file."""        try:            data = {                'transactions': [t.to_dict() for t in self.transactions],                'budgets': self.budgets            }            with open(self.filename, 'w', encoding='utf-8') as f:                json.dump(data, f, indent=2)        except Exception as e:            print(f"Error saving: {e}")        def load(self):        """Load from JSON file."""        try:            with open(self.filename, 'r', encoding='utf-8') as f:                data = json.load(f)                self.transactions = [                    Transaction.from_dict(t) for t in data.get('transactions', [])                ]                self.budgets = data.get('budgets', {})        except FileNotFoundError:            self.transactions = []            self.budgets = {}        except Exception as e:            print(f"Error loading: {e}")        def export_csv(self, filename):        """Export transactions to CSV."""        import csv        try:            with open(filename, 'w', newline='', encoding='utf-8') as f:                writer = csv.writer(f)                writer.writerow(['Date', 'Type', 'Category', 'Amount', 'Description'])                                for t in self.transactions:                    writer.writerow([                        t.date.strftime('%Y-%m-%d'),                        t.trans_type,                        t.category,                        t.amount,                        t.description                    ])            return True        except Exception as e:            print(f"Export failed: {e}")            return False

Bước 2: Main Application

# finance_app.pydef display_menu():    """Display main menu."""    print("\n" + "="*50)    print("💰 PERSONAL FINANCE TRACKER")    print("="*50)    print("1. Add Income")    print("2. Add Expense")    print("3. View Balance")    print("4. Monthly Report")    print("5. Set Budget")    print("6. View Budgets")    print("7. Export to CSV")    print("0. Exit")    print("="*50) def add_income(tracker):    """Add income transaction."""    print("\n--- Add Income ---")    try:        amount = float(input("Amount: $"))        category = input(f"Category {Transaction.CATEGORIES}: ").strip()        description = input("Description: ").strip()                transaction = Transaction(amount, category, description, 'income')        tracker.add_transaction(transaction)        print(f"✅ Income added: +${amount:.2f}")    except ValueError as e:        print(f"❌ Error: {e}") def add_expense(tracker):    """Add expense transaction."""    print("\n--- Add Expense ---")    try:        amount = float(input("Amount: $"))        category = input(f"Category {Transaction.CATEGORIES}: ").strip()        description = input("Description: ").strip()                transaction = Transaction(amount, category, description, 'expense')        tracker.add_transaction(transaction)        print(f"✅ Expense added: -${amount:.2f}")    except ValueError as e:        print(f"❌ Error: {e}") def view_balance(tracker):    """View current balance."""    balance = tracker.get_balance()    print(f"\n💵 Current Balance: ${balance:.2f}") def monthly_report(tracker):    """Display monthly report."""    now = datetime.now()    year = int(input(f"Year [{now.year}]: ") or now.year)    month = int(input(f"Month [{now.month}]: ") or now.month)        summary = tracker.get_monthly_summary(year, month)        print(f"\n📊 Report for {month}/{year}")    print("="*40)    print(f"Income:  +${summary['income']:.2f}")    print(f"Expense: -${summary['expense']:.2f}")    print(f"Balance:  ${summary['balance']:.2f}")    print(f"\nTransactions: {summary['transaction_count']}")        if summary['by_category']:        print("\n--- Expenses by Category ---")        for category, amount in sorted(summary['by_category'].items(),                                       key=lambda x: x[1], reverse=True):            percentage = (amount / summary['expense'] * 100) if summary['expense'] > 0 else 0            print(f"{category:15} ${amount:8.2f} ({percentage:5.1f}%)") def set_budget(tracker):    """Set budget for category."""    print(f"\nCategories: {', '.join(Transaction.CATEGORIES)}")    category = input("Category: ").strip().lower()    amount = float(input("Budget amount: $"))        tracker.set_budget(category, amount)    print(f"✅ Budget set: {category} = ${amount:.2f}") def view_budgets(tracker):    """View all budgets."""    if not tracker.budgets:        print("\n📋 No budgets set.")        return        print("\n--- Current Budgets ---")    now = datetime.now()        for category, budget in tracker.budgets.items():        spent = tracker.get_category_spending(            category,            datetime(now.year, now.month, 1)        )        remaining = budget - spent        percentage = (spent / budget * 100) if budget > 0 else 0                print(f"\n{category.upper()}")        print(f"  Budget: ${budget:.2f}")        print(f"  Spent:  ${spent:.2f} ({percentage:.1f}%)")        print(f"  Left:   ${remaining:.2f}")                if remaining < 0:            print(f"  ⚠️  OVER BUDGET!") def main():    """Main application."""    tracker = FinanceTracker()        while True:        display_menu()        choice = input("\nChoice: ").strip()                if choice == '1':            add_income(tracker)        elif choice == '2':            add_expense(tracker)        elif choice == '3':            view_balance(tracker)        elif choice == '4':            monthly_report(tracker)        elif choice == '5':            set_budget(tracker)        elif choice == '6':            view_budgets(tracker)        elif choice == '7':            filename = f"finance_export_{datetime.now().strftime('%Y%m%d')}.csv"            if tracker.export_csv(filename):                print(f"✅ Exported to {filename}")        elif choice == '0':            print("\n👋 Goodbye!")            break        else:            print("❌ Invalid choice!") if __name__ == "__main__":    main()

Mở rộng thêm:

  • Recurring transactions (monthly bills)
  • Multiple accounts support
  • Charts và visualizations
  • Currency conversion
  • Receipt photo storage
  • Financial goals tracking

Project 3: Student Grade Management System 📚

Mô tả: Hệ thống quản lý điểm sinh viên cho giáo viên.

Yêu cầu chức năng:

  • Quản lý students (add, edit, delete)
  • Quản lý courses/subjects
  • Nhập điểm cho từng môn
  • Tính GPA tự động
  • Xếp hạng học lực
  • Export báo cáo (transcript)
  • Statistics và analytics

Kiến thức sử dụng:

  • OOP (Student, Course, Grade classes)
  • File I/O (JSON/CSV)
  • Data processing
  • Sorting và filtering
  • Error handling
  • Properties

Hướng dẫn thực hiện:

Bước 1: Core Classes

# student_management.pyfrom datetime import datetimeimport json class Grade:    """Represents a grade for a course."""        def __init__(self, course_name, score, credits, semester):        self.course_name = course_name        self.score = float(score)        self.credits = int(credits)        self.semester = semester        self.date = datetime.now()        @property    def letter_grade(self):        """Convert score to letter grade."""        if self.score >= 90:            return 'A'        elif self.score >= 80:            return 'B'        elif self.score >= 70:            return 'C'        elif self.score >= 60:            return 'D'        else:            return 'F'        @property    def grade_point(self):        """Convert to grade point (4.0 scale)."""        if self.score >= 90:            return 4.0        elif self.score >= 80:            return 3.0        elif self.score >= 70:            return 2.0        elif self.score >= 60:            return 1.0        else:            return 0.0        def to_dict(self):        return {            'course_name': self.course_name,            'score': self.score,            'credits': self.credits,            'semester': self.semester,            'date': self.date.isoformat()        }        @classmethod    def from_dict(cls, data):        grade = cls(            data['course_name'],            data['score'],            data['credits'],            data['semester']        )        grade.date = datetime.fromisoformat(data['date'])        return grade class Student:    """Represents a student."""        def __init__(self, student_id, name, email):        self.student_id = student_id        self.name = name        self.email = email        self.grades = []        self.enrolled_date = datetime.now()        def add_grade(self, grade):        """Add a grade."""        self.grades.append(grade)        def remove_grade(self, course_name, semester):        """Remove a grade."""        self.grades = [            g for g in self.grades            if not (g.course_name == course_name and g.semester == semester)        ]        def get_grades_by_semester(self, semester):        """Get grades for specific semester."""        return [g for g in self.grades if g.semester == semester]        @property    def gpa(self):        """Calculate overall GPA."""        if not self.grades:            return 0.0                total_points = sum(g.grade_point * g.credits for g in self.grades)        total_credits = sum(g.credits for g in self.grades)                return total_points / total_credits if total_credits > 0 else 0.0        def get_semester_gpa(self, semester):        """Calculate GPA for specific semester."""        semester_grades = self.get_grades_by_semester(semester)        if not semester_grades:            return 0.0                total_points = sum(g.grade_point * g.credits for g in semester_grades)        total_credits = sum(g.credits for g in semester_grades)                return total_points / total_credits if total_credits > 0 else 0.0        @property    def total_credits(self):        """Get total credits earned."""        return sum(g.credits for g in self.grades if g.grade_point > 0)        @property    def academic_standing(self):        """Determine academic standing."""        gpa = self.gpa        if gpa >= 3.5:            return "Excellent"        elif gpa >= 3.0:            return "Good"        elif gpa >= 2.0:            return "Satisfactory"        else:            return "Warning"        def to_dict(self):        return {            'student_id': self.student_id,            'name': self.name,            'email': self.email,            'grades': [g.to_dict() for g in self.grades],            'enrolled_date': self.enrolled_date.isoformat()        }        @classmethod    def from_dict(cls, data):        student = cls(data['student_id'], data['name'], data['email'])        student.grades = [Grade.from_dict(g) for g in data.get('grades', [])]        student.enrolled_date = datetime.fromisoformat(data['enrolled_date'])        return student        def __str__(self):        return f"{self.name} ({self.student_id}) - GPA: {self.gpa:.2f}" class GradeBook:    """Manages collection of students."""        def __init__(self, filename='gradebook.json'):        self.filename = filename        self.students = []        self.load()        def add_student(self, student):        """Add new student."""        if self.find_student(student.student_id):            raise ValueError("Student ID already exists")        self.students.append(student)        self.save()        def remove_student(self, student_id):        """Remove student."""        student = self.find_student(student_id)        if student:            self.students.remove(student)            self.save()            return True        return False        def find_student(self, student_id):        """Find student by ID."""        for student in self.students:            if student.student_id == student_id:                return student        return None        def get_top_students(self, n=10):        """Get top N students by GPA."""        return sorted(self.students, key=lambda s: s.gpa, reverse=True)[:n]        def get_class_statistics(self):        """Get class statistics."""        if not self.students:            return {}                gpas = [s.gpa for s in self.students]                return {            'total_students': len(self.students),            'average_gpa': sum(gpas) / len(gpas),            'highest_gpa': max(gpas),            'lowest_gpa': min(gpas),            'excellent': sum(1 for s in self.students if s.academic_standing == "Excellent"),            'good': sum(1 for s in self.students if s.academic_standing == "Good"),            'satisfactory': sum(1 for s in self.students if s.academic_standing == "Satisfactory"),            'warning': sum(1 for s in self.students if s.academic_standing == "Warning")        }        def save(self):        """Save to JSON."""        try:            data = [s.to_dict() for s in self.students]            with open(self.filename, 'w', encoding='utf-8') as f:                json.dump(data, f, indent=2, ensure_ascii=False)        except Exception as e:            print(f"Error saving: {e}")        def load(self):        """Load from JSON."""        try:            with open(self.filename, 'r', encoding='utf-8') as f:                data = json.load(f)                self.students = [Student.from_dict(s) for s in data]        except FileNotFoundError:            self.students = []        except Exception as e:            print(f"Error loading: {e}")            self.students = []

Tiếp tục với CLI interface tương tự các project trên...

Mở rộng thêm:

  • Attendance tracking
  • Assignment/homework management
  • Parent portal view
  • Grade distribution charts
  • Export transcripts to PDF
  • Email notifications

Bài Tập Tự Làm: Inventory Management System 📦

Mô tả: Xây dựng hệ thống quản lý kho hàng cho cửa hàng nhỏ.

Yêu cầu chức năng:

Core Features:

  1. Product Management

    • Add/Edit/Delete products
    • Product info: name, SKU, price, quantity, category
    • Low stock alerts
    • Product search và filtering
  2. Inventory Operations

    • Stock in (nhập hàng)
    • Stock out (xuất hàng/bán)
    • Stock adjustment (điều chỉnh)
    • Transaction history
  3. Reporting

    • Current inventory report
    • Stock movement report
    • Low stock report
    • Value calculation (total inventory value)
  4. Data Management

    • Save/Load from JSON
    • Export to CSV
    • Backup và restore

Hướng Dẫn Chi Tiết:

1. Thiết Kế Classes

class Product:    """    Attributes:    - sku (str): Stock Keeping Unit - mã sản phẩm    - name (str): Tên sản phẩm    - category (str): Danh mục    - price (float): Giá bán    - quantity (int): Số lượng hiện có    - min_quantity (int): Ngưỡng cảnh báo    - created_at (datetime): Ngày tạo        Methods:    - to_dict(): Convert to dictionary    - from_dict(data): Create from dictionary    - is_low_stock(): Check if quantity < min_quantity    - update_quantity(amount): Cập nhật số lượng    - get_value(): Tính giá trị (price * quantity)    """    pass class Transaction:    """    Represents inventory transaction.        Attributes:    - transaction_id (str): Unique ID    - sku (str): Product SKU    - trans_type (str): 'in', 'out', 'adjust'    - quantity (int): Số lượng thay đổi    - note (str): Ghi chú    - date (datetime): Ngày giao dịch        Methods:    - to_dict()    - from_dict(data)    """    pass class Inventory:    """    Manages products and transactions.        Attributes:    - products (dict): {sku: Product}    - transactions (list): List of Transaction    - filename (str): JSON file path        Methods:    - add_product(product): Thêm sản phẩm mới    - remove_product(sku): Xóa sản phẩm    - find_product(sku): Tìm sản phẩm    - stock_in(sku, quantity, note): Nhập hàng    - stock_out(sku, quantity, note): Xuất hàng    - adjust_stock(sku, quantity, note): Điều chỉnh    - get_low_stock_products(): Sản phẩm sắp hết    - get_total_value(): Tổng giá trị kho    - get_transactions(sku=None, start_date=None): Lịch sử    - save(): Lưu vào JSON    - load(): Load từ JSON    - export_csv(filename): Export báo cáo    """    pass

2. Validation Requirements

# Product validation- SKU: Unique, alphanumeric, 6-12 characters- Name: Not empty, max 100 characters- Price: >= 0- Quantity: >= 0- Category: From predefined list # Transaction validation- Quantity: > 0- SKU: Must exist in inventory- stock_out: quantity <= current quantity

3. Features Chi Tiết

Low Stock Alert:

def check_low_stock(self):    """Return list of products below minimum."""    return [p for p in self.products.values() if p.is_low_stock()]

Inventory Value:

def get_total_value(self):    """Calculate total inventory value."""    return sum(p.get_value() for p in self.products.values())

Search Products:

def search_products(self, query):    """    Search by SKU, name, or category.    Return matching products.    """    pass

Transaction Report:

def get_transaction_report(self, start_date, end_date):    """    Get transactions in date range.    Return summary: total_in, total_out, net_change    """    pass

4. CLI Interface Requirements

=== INVENTORY MANAGEMENT SYSTEM ===1. Add Product2. View All Products3. Search Product4. Update Product5. Delete Product6. Stock In7. Stock Out8. Adjust Stock9. Low Stock Alert10. Inventory Report11. Transaction History12. Export to CSV0. Exit

5. Testing Checklist

  • ✅ Add product với valid data
  • ✅ Add product với duplicate SKU (should fail)
  • ✅ Stock out nhiều hơn quantity (should fail)
  • ✅ Low stock detection
  • ✅ Total value calculation
  • ✅ Save/Load data
  • ✅ Search functionality
  • ✅ Export CSV

6. Sample Data

# Create sample productsproducts = [    Product("LAPTOP01", "Dell XPS 13", "Electronics", 1200.00, 15, 5),    Product("MOUSE01", "Logitech MX Master", "Accessories", 99.99, 50, 10),    Product("KB01", "Mechanical Keyboard", "Accessories", 150.00, 30, 10),] # Sample transactionsinventory.stock_in("LAPTOP01", 10, "Restock from supplier")inventory.stock_out("LAPTOP01", 2, "Sold to customer #123")inventory.adjust_stock("MOUSE01", -5, "Damaged items")

7. Bonus Features (Optional)

  • Categories Management: CRUD operations for categories
  • Suppliers: Track suppliers for each product
  • Barcode Support: Generate/scan barcodes
  • Multi-location: Support multiple warehouse locations
  • Reorder Automation: Auto-suggest reorder when low stock
  • Sales Analytics: Best-selling products, revenue tracking
  • User Authentication: Login system for multiple users

8. Code Structure

inventory_system/├── models/│   ├── __init__.py│   ├── product.py        # Product class│   ├── transaction.py    # Transaction class│   └── inventory.py      # Inventory class├── utils/│   ├── __init__.py│   ├── validators.py     # Validation functions│   └── helpers.py        # Helper functions├── main.py               # CLI application├── test_inventory.py     # Unit tests└── data/    └── inventory.json    # Data storage

9. Học Được Gì?

  • ✅ OOP design patterns
  • ✅ Data validation
  • ✅ File I/O (JSON, CSV)
  • ✅ Error handling
  • ✅ Date/time operations
  • ✅ List/dict operations
  • ✅ Search algorithms
  • ✅ Report generation
  • ✅ CLI interface design
  • ✅ Testing strategies

10. Tips

  • Bắt đầu với basic features trước
  • Test từng function riêng biệt
  • Sử dụng docstrings cho mọi class/method
  • Handle errors gracefully
  • Save data sau mỗi operation quan trọng
  • Code có cấu trúc, dễ đọc
  • Đặt tên variables/functions rõ ràng

Tổng Kết

🎉 Chúc mừng! Bạn đã hoàn thành Module Python Cơ Bản!

Đã học được:

  • ✅ 15 bài học Python cơ bản đầy đủ
  • ✅ 3 project mẫu với code hoàn chỉnh
  • ✅ 1 project tự làm với hướng dẫn chi tiết
  • ✅ Best practices và design patterns
  • ✅ Real-world applications

Tiếp theo:

  • 📚 Module 02: Python Advanced - Decorators, Generators, Async, Testing
  • 🌐 Module 03: Django Basic - Web development với Django
  • 🚀 Module 04: Django Advanced - Production-ready applications

Lời khuyên:

  • Practice mỗi ngày với các projects nhỏ
  • Đọc code của người khác (GitHub)
  • Tham gia coding challenges (LeetCode, HackerRank)
  • Build your own projects
  • Contribute to open source

Keep coding! 💻


Remember:

  • Practice makes perfect
  • Start small, think big
  • Code quality > Code quantity
  • Test your code
  • Document everything!