Python Program to Demonstrate — Mini Projects (From Beginner to Pro Style)
Learn Python step by step.
All about Python - — Mini Projects (From Beginner to Pro Style)
Jan 26, 2026
# Chapter 17 — Mini Projects (From Beginner to Pro Style)
This chapter is a menu. Pick one and build it fully.
## 17.1 Meetcode CLI Notes
Goal: A simple CLI tool that stores, lists, and deletes notes.
This project is realistic because it involves file handling, argument parsing, data structures, and handling edge cases.
### What the user can do
- Add note (text + optional tag)
- List notes (latest first)
- Delete note by id
- Store the data in a file (`notes.json`)
### Diagram: Flow
```text
CLI command
|
+--> load notes.json (if exists)
|
+--> perform action (add/list/delete)
|
+--> save notes.json (if changed)
|
+--> print clean output
```
### Full working code (single file)
Save as `meetcode_notes.py`:
```python
import argparse
import json
from dataclasses import dataclass, asdict
from datetime import datetime, timezone
from pathlib import Path
DATA_FILE = Path("notes.json")
@dataclass
class Note:
id: int
text: str
tag: str
created_at: str
def now_iso():
return datetime.now(timezone.utc).isoformat(timespec="seconds")
def load_notes(path: Path):
if not path.exists():
return []
raw = path.read_text(encoding="utf-8").strip()
if not raw:
return []
data = json.loads(raw)
notes = []
for item in data:
notes.append(Note(**item))
return notes
def save_notes(path: Path, notes):
tmp = path.with_suffix(".tmp")
payload = [asdict(n) for n in notes]
tmp.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
tmp.replace(path)
def next_id(notes):
if not notes:
return 1
return max(n.id for n in notes) + 1
def cmd_add(args):
notes = load_notes(DATA_FILE)
note = Note(
id=next_id(notes),
text=args.text.strip(),
tag=(args.tag or "").strip(),
created_at=now_iso(),
)
notes.append(note)
save_notes(DATA_FILE, notes)
print(f"Added note #{note.id}")
def cmd_list(args):
notes = load_notes(DATA_FILE)
notes_sorted = sorted(notes, key=lambda n: n.created_at, reverse=True)
if args.tag:
t = args.tag.strip()
notes_sorted = [n for n in notes_sorted if n.tag == t]
if not notes_sorted:
print("No notes found.")
return
for n in notes_sorted:
tag = f" [{n.tag}]" if n.tag else ""
print(f"#{n.id}{tag} {n.created_at}")
print(n.text)
print("-" * 40)
def cmd_delete(args):
notes = load_notes(DATA_FILE)
before = len(notes)
notes = [n for n in notes if n.id != args.id]
after = len(notes)
if after == before:
print(f"Note #{args.id} not found.")
return
save_notes(DATA_FILE, notes)
print(f"Deleted note #{args.id}")
def build_parser():
p = argparse.ArgumentParser(prog="meetcode-notes")
sub = p.add_subparsers(dest="cmd", required=True)
p_add = sub.add_parser("add", help="Add a note")
p_add.add_argument("text", help="Note text")
p_add.add_argument("--tag", default="", help="Optional tag")
p_add.set_defaults(fn=cmd_add)
p_list = sub.add_parser("list", help="List notes")
p_list.add_argument("--tag", default="", help="Filter by tag")
p_list.set_defaults(fn=cmd_list)
p_del = sub.add_parser("delete", help="Delete by id")
p_del.add_argument("id", type=int, help="Note id")
p_del.set_defaults(fn=cmd_delete)
return p
def main():
parser = build_parser()
args = parser.parse_args()
args.fn(args)
if __name__ == "__main__":
main()
```
### How to run (example)
```bash
python meetcode_notes.py add "Buy milk" --tag personal
python meetcode_notes.py add "Fix CSV header issue" --tag work
python meetcode_notes.py list
python meetcode_notes.py list --tag work
python meetcode_notes.py delete 1
```
### logic checks (edge cases)
- The tool will not crash if `notes.json` is missing.
- If the file is empty, handle it safely.
- delete me wrong id how to clear message
- When saving in `.tmp` format, the risk of data corruption is reduced.
## 17.2 CSV Cleaner
Goal: Read a CSV, normalize headers, remove empty rows, write a clean CSV.
### What “normalize headers” means (simple rule)
- `Name` → `name`
- `User Name` → `user_name`
- `User-Name` → `user_name`
- multiple spaces → single underscore
- Making duplicate header names unique (e.g., `name`, `name_2`)
### Diagram: Cleaner Pipeline
```text
raw.csv
|
+--> read header
| |
| +--> normalize header names
|
+--> read rows
|
+--> drop rows where all cells are blank
|
+--> write cleaned rows
|
clean.csv
```
### Full working code (single file)
Save as `csv_cleaner.py`:
```python
import argparse
import csv
import re
from pathlib import Path
def normalize_header(name: str):
s = name.strip().lower()
s = re.sub(r"[s-]+", "_", s)
s = re.sub(r"[^a-z0-9_]", "", s)
s = re.sub(r"_+", "_", s).strip("_")
return s or "col"
def unique_headers(headers):
used = {}
out = []
for h in headers:
base = h
if base not in used:
used[base] = 1
out.append(base)
else:
used[base] += 1
out.append(f"{base}_{used[base]}")
return out
def is_empty_row(row):
for v in row:
if str(v).strip() != "":
return False
return True
def clean_csv(input_path: Path, output_path: Path):
with input_path.open("r", encoding="utf-8", newline="") as f:
reader = csv.reader(f)
try:
raw_header = next(reader)
except StopIteration:
raise ValueError("Input CSV is empty.")
normalized = [normalize_header(h) for h in raw_header]
header = unique_headers(normalized)
rows = []
for row in reader:
if is_empty_row(row):
continue
if len(row) < len(header):
row = row + [""] * (len(header) - len(row))
elif len(row) > len(header):
row = row[: len(header)]
rows.append(row)
with output_path.open("w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(header)
writer.writerows(rows)
return {"rows_written": len(rows), "columns": len(header)}
def main():
p = argparse.ArgumentParser(prog="csv-cleaner")
p.add_argument("input", help="Input CSV path")
p.add_argument("output", help="Output CSV path")
args = p.parse_args()
info = clean_csv(Path(args.input), Path(args.output))
print(f"Cleaned CSV written: {args.output}")
print(f"Columns: {info['columns']}, Rows: {info['rows_written']}")
if __name__ == "__main__":
main()
```
### How to run (example)
```bash
python csv_cleaner.py raw.csv clean.csv
```
### logic checks (edge cases)
- Empty CSV file: how to clear the error
- Row length mismatch (too short or too long) can be adjusted.
- Duplicate handlers are successfully renamed.
## 17.3 OOP Project: Library System
Goal: A small "library management" system that demonstrates OOP core concepts in a real-world scenario.
### Real thinking: Where will the data be stored?
- Books: Looking for unique Eid gifts (ISBN is preferred)
- Members: A unique member ID is required.
- Loans: Which book is with which member?
### Diagram: Objects relation
```text
Library
|
+--> books (isbn -> Book)
|
+--> members (member_id -> Member)
|
+--> loans (isbn -> member_id)
```
### Full working code (single file)
Save as `library_system.py`:
```python
from dataclasses import dataclass
import re
@dataclass(frozen=True)
class Book:
isbn: str
title: str
author: str
class Member:
def __init__(self, member_id: str, name: str):
self.member_id = member_id
self.name = name
@property
def member_id(self):
return self._member_id
@member_id.setter
def member_id(self, value):
value = str(value).strip()
if not re.fullmatch(r"[A-Z]-d{3,6}", value):
raise ValueError("member_id format must look like S-101 or T-5001")
self._member_id = value
def member_type(self):
return "member"
def __repr__(self):
return f"{self.__class__.__name__}(member_id={self.member_id!r}, name={self.name!r})"
class StudentMember(Member):
def member_type(self):
return "student"
class TeacherMember(Member):
def member_type(self):
return "teacher"
class Library:
def __init__(self, name: str):
self.name = name
self._books = {}
self._members = {}
self._loans = {}
def add_book(self, book: Book):
isbn = book.isbn.strip()
if isbn in self._books:
raise ValueError(f"Book already exists: {isbn}")
self._books[isbn] = book
def register_member(self, member: Member):
if member.member_id in self._members:
raise ValueError(f"Member already exists: {member.member_id}")
self._members[member.member_id] = member
def is_available(self, isbn: str):
isbn = isbn.strip()
return isbn in self._books and isbn not in self._loans
def lend(self, isbn: str, member_id: str):
isbn = isbn.strip()
member_id = member_id.strip()
if isbn not in self._books:
raise ValueError("Unknown book ISBN")
if member_id not in self._members:
raise ValueError("Unknown member id")
if isbn in self._loans:
current = self._loans[isbn]
raise ValueError(f"Book already loaned to {current}")
self._loans[isbn] = member_id
def return_book(self, isbn: str):
isbn = isbn.strip()
if isbn not in self._loans:
raise ValueError("This book is not currently loaned.")
del self._loans[isbn]
def list_available_books(self):
out = []
for isbn, book in self._books.items():
if isbn not in self._loans:
out.append(book)
return out
def list_loans(self):
out = []
for isbn, member_id in self._loans.items():
out.append((self._books[isbn], self._members[member_id]))
return out
def demo():
lib = Library("Meetcode Library")
lib.add_book(Book(isbn="978-1", title="Python Basics", author="Team Meetcode"))
lib.add_book(Book(isbn="978-2", title="OOP in Practice", author="Team Meetcode"))
s1 = StudentMember("S-101", "Asha")
t1 = TeacherMember("T-5001", "Mr. Ravi")
lib.register_member(s1)
lib.register_member(t1)
print("Available:", lib.list_available_books())
lib.lend("978-2", "S-101")
print("Loans:", lib.list_loans())
print("Available:", lib.list_available_books())
lib.return_book("978-2")
print("Available:", lib.list_available_books())
if __name__ == "__main__":
demo()
```
### Why this is ?
- ID verification `@property` me: Stop if an incorrect ID is received.
- The details inside the library are clear: books, members, and loans are all separate.
- The rules for `lend()` are clear: unknown book, unknown member, already loaned out.
### Upgrade ideas (Beginner → Pro)
- Save the loan to a file (JSON)
- Add due date, calculate fines
- Search feature (title/author)
- Multiple copies of the same book (counting system)
---
## Final Quick Map (Everything You Learned)
```text
Basics -> Data -> Control -> Functions -> Files -> Errors -> Imports
-> OOP (inheritance + properties) -> Iteration -> Decorators
-> Types -> Async -> Testing -> Performance -> Projects
```
```
## Conclusion
In this article, we explored the core concepts of All about Python - — Mini Projects (From Beginner to Pro Style). Understanding these fundamentals is crucial for any developer looking to master this topic.
## Frequently Asked Questions (FAQs)
**Q: What is All about Python - — Mini Projects (From Beginner to Pro Style)?**
A: All about Python - — Mini Projects (From Beginner to Pro Style) is a fundamental concept in this programming language/topic that allows developers to perform specific tasks efficiently.
**Q: Why is All about Python - — Mini Projects (From Beginner to Pro Style) important?**
A: It helps in organizing code, improving performance, and implementing complex logic in a structured way.
**Q: How to get started with All about Python - — Mini Projects (From Beginner to Pro Style)?**
A: You can start by practicing the basic syntax and examples provided in this tutorial.
**Q: Are there any prerequisites for All about Python - — Mini Projects (From Beginner to Pro Style)?**
A: Basic knowledge of programming logic and syntax is recommended.
**Q: Can All about Python - — Mini Projects (From Beginner to Pro Style) be used in real-world projects?**
A: Yes, it is widely used in enterprise-level applications and software development.
**Q: Where can I find more examples of All about Python - — Mini Projects (From Beginner to Pro Style)?**
A: You can check our blog section for more advanced tutorials and use cases.
**Q: Is All about Python - — Mini Projects (From Beginner to Pro Style) suitable for beginners?**
A: Yes, our guide is designed to be beginner-friendly with clear explanations.
**Q: How does All about Python - — Mini Projects (From Beginner to Pro Style) improve code quality?**
A: By providing a standardized way to handle logic, it makes code more readable and maintainable.
**Q: What are common mistakes when using All about Python - — Mini Projects (From Beginner to Pro Style)?**
A: Common mistakes include incorrect syntax usage and not following best practices, which we've covered here.
**Q: Does this tutorial cover advanced All about Python - — Mini Projects (From Beginner to Pro Style)?**
A: This article covers the essentials; stay tuned for our advanced series on this topic.