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:
- ✅ Giới thiệu Python
- ✅ Variables & Data Types
- ✅ Operators
- ✅ Strings
- ✅ Lists
- ✅ Tuples
- ✅ Dictionaries
- ✅ Sets
- ✅ Control Flow
- ✅ Loops
- ✅ Functions
- ✅ Modules & Packages
- ✅ File I/O
- ✅ Error Handling
- ✅ 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:
Product Management
- Add/Edit/Delete products
- Product info: name, SKU, price, quantity, category
- Low stock alerts
- Product search và filtering
Inventory Operations
- Stock in (nhập hàng)
- Stock out (xuất hàng/bán)
- Stock adjustment (điều chỉnh)
- Transaction history
Reporting
- Current inventory report
- Stock movement report
- Low stock report
- Value calculation (total inventory value)
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!