Ready for a tiny but mighty project you can finish in one sitting?
Create a Command‑Line Daily Journal that lets you jot down thoughts, ideas, or anything you want to remember – and saves each entry to a nicely‑formatted markdown file with a timestamp. No GUI, no databases, just pure Python and the power of plain text.
Why this works
- File handling (
-
-
- The whole thing runs in the terminal, so you can launch it from any shell or even bind it to a keyboard shortcut.
How you’ll build it
1. Ask the user for a journal entry.
Use a simple loop that reads lines until the user submits an empty line (just hit Enter).
2. Add a header with the current date & time.
3. Append the entry to a markdown file.
Opening the file with mode
4. Store the file in a dedicated folder.
With
What you’ll learn
- Converting user input into a multi‑line string.
- Using
- Formatting strings with f‑strings (you may already know them, but they shine here).
- Creating directories on the fly if they don’t exist (
A quick sketch of the code
Give it a spin
1. Save the script as
2. Run it:
3. Type a few lines, hit Enter on a blank line, and watch the markdown file grow.
Next steps (optional)
- Add a
- Use the
- Convert the markdown to HTML for a simple web‑based view.
That’s it – a functional, personal journal you can start using right away, and a solid foundation for many future tweaks. Happy writing!
Create a Command‑Line Daily Journal that lets you jot down thoughts, ideas, or anything you want to remember – and saves each entry to a nicely‑formatted markdown file with a timestamp. No GUI, no databases, just pure Python and the power of plain text.
Why this works
- File handling (
open, write, close) lets you append data to a file without overwriting the old stuff. -
datetime gives you the exact date and time, so each entry is clearly marked. -
pathlib (the modern way to work with paths) makes the script portable across Windows, macOS, and Linux. - The whole thing runs in the terminal, so you can launch it from any shell or even bind it to a keyboard shortcut.
How you’ll build it
1. Ask the user for a journal entry.
Use a simple loop that reads lines until the user submits an empty line (just hit Enter).
2. Add a header with the current date & time.
datetime.now().strftime("%Y-%m-%d %H:%M") formats the timestamp the way we like to see it. 3. Append the entry to a markdown file.
Opening the file with mode
'a' (append) ensures previous entries stay untouched. 4. Store the file in a dedicated folder.
With
pathlib.Path.home() / "journal" you automatically place the journal in the user’s home directory, keeping everything tidy.What you’ll learn
- Converting user input into a multi‑line string.
- Using
with open(...) as f: to safely manage file resources (no need to call close). - Formatting strings with f‑strings (you may already know them, but they shine here).
- Creating directories on the fly if they don’t exist (
Path.mkdir(parents=True, exist_ok=True)).A quick sketch of the code
import sys
from datetime import datetime
from pathlib import Path
# ---------- configuration ----------
journal_dir = Path.home() / "journal"
journal_file = journal_dir / "daily.md"
journal_dir.mkdir(parents=True, exist_ok=True)
# -----------------------------------
def collect_entry():
print("Enter your journal entry. Press Enter on an empty line to finish.")
lines = []
for line in sys.stdin:
line = line.rstrip("\n")
if line == "":
break
lines.append(line)
return "\n".join(lines)
def save_entry(text: str):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
header = f"\n## {timestamp}\n\n"
with journal_file.open("a", encoding="utf-8") as f:
f.write(header + text + "\n")
if __name__ == "__main__":
entry = collect_entry()
if entry.strip():
save_entry(entry)
print(f"✅ Entry saved to {journal_file}")
else:
print("⚠️ No text entered – nothing saved.")
Give it a spin
1. Save the script as
journal.py. 2. Run it:
python journal.py. 3. Type a few lines, hit Enter on a blank line, and watch the markdown file grow.
Next steps (optional)
- Add a
--list flag to print the last 5 entries. - Use the
rich library to colour‑code the terminal output. - Convert the markdown to HTML for a simple web‑based view.
That’s it – a functional, personal journal you can start using right away, and a solid foundation for many future tweaks. Happy writing!
Ever wondered why a
What is
- The
- If the loop exits early because of a
Why does this work?
Python’s
When is it useful?
- Searching for something in a list and wanting to know “was it found?” without using an extra variable.
- Validating input where you need to stop early on failure but otherwise confirm success.
Simple example: finding a prime number
What happens here?
- The inner loop tests divisibility. If a divisor is found, it
- If the inner loop never breaks (i.e., no divisor was found), its
- The outer
Quick checklist (bolded list)
Use
- You need to know whether the loop completed normally
- You want to avoid an extra found flag variable
Avoid it when
- The logic becomes harder to read than a simple flag
- You’re working with very nested loops that confuse the flow
Give it a try in your next search‑or‑validate task—you’ll see how cleanly it expresses “did we finish without interruption?”.
for loop sometimes seems to have an extra part at the end? Python has a hidden gem called the for … else construct. It looks strange at first, but once you get it, it can make your code clearer and avoid extra flags.What is
else doing after a loop? - The
else block runs only if the loop finishes all its iterations without hitting a break. - If the loop exits early because of a
break, the else part is skipped.Why does this work?
Python’s
for statement is actually a control flow structure that can have three parts: the iterator, the body, and an optional else clause. Internally, after each iteration Python checks whether a break was executed. If not, it falls through to the else block once the iterator is exhausted.When is it useful?
- Searching for something in a list and wanting to know “was it found?” without using an extra variable.
- Validating input where you need to stop early on failure but otherwise confirm success.
Simple example: finding a prime number
numbers = [4, 6, 8, 9, 10, 11, 12]
for n in numbers:
# check if n is prime
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0: # found a divisor → not prime
break # exit inner loop early
else: # no break → n is prime
print(f"{n} is the first prime we met!")
break # stop outer loop once we found it
else:
print("No prime numbers in the list.")
What happens here?
- The inner loop tests divisibility. If a divisor is found, it
breaks, meaning “this number isn’t prime” and the else of the inner loop is skipped. - If the inner loop never breaks (i.e., no divisor was found), its
else runs, signaling that the current n is prime. - The outer
else would only run if we never hit a break in the outer loop—meaning we never found a prime at all.Quick checklist (bolded list)
Use
for … else when - You need to know whether the loop completed normally
- You want to avoid an extra found flag variable
Avoid it when
- The logic becomes harder to read than a simple flag
- You’re working with very nested loops that confuse the flow
Give it a try in your next search‑or‑validate task—you’ll see how cleanly it expresses “did we finish without interruption?”.
Ever opened your Downloads folder and wondered why it’s exploding with copies of the same file?
A quick duplicate‑file finder can clean that up in minutes, and you can build one from scratch in a single sitting.
What you’ll need
- pathlib – modern, object‑oriented way to work with file paths (instead of the old
- hashlib – creates a digital fingerprint (hash) of a file’s contents; identical files produce identical hashes.
- collections.defaultdict – a dictionary that automatically creates a list for each new key, perfect for grouping files by their hash.
- os – for walking through directories (
- (optional) tqdm – a tiny progress bar so you can see the scan move.
How it works, step by step
1. Walk the folder –
2. Hash each file – open the file in binary mode, read it chunk‑by‑chunk (e.g., 64 KB blocks) and feed those bytes into
3. Group by hash – store the resulting hash as a key in a
4. Report duplicates – after the scan, any hash with more than one path means those files are byte‑for‑byte identical. Print them out, or later add a prompt to delete the extras.
Why hashing is reliable
A SHA‑256 hash is 256 bits long; the chance of two different files sharing the same hash (a collision) is astronomically low—practically zero for everyday use. So comparing hashes is far faster than comparing every file byte‑by‑byte.
Mini‑example (core logic)
What you can add next
- Command‑line arguments with
- Progress bar via
- Export the report to a CSV or JSON file for later review.
Give it a try: point the script at a cluttered directory, run it, and watch the list of duplicates appear. You’ll see how a few standard libraries can turn a messy folder into a tidy workspace in minutes.
Happy cleaning! 🚀
A quick duplicate‑file finder can clean that up in minutes, and you can build one from scratch in a single sitting.
What you’ll need
- pathlib – modern, object‑oriented way to work with file paths (instead of the old
os.path). - hashlib – creates a digital fingerprint (hash) of a file’s contents; identical files produce identical hashes.
- collections.defaultdict – a dictionary that automatically creates a list for each new key, perfect for grouping files by their hash.
- os – for walking through directories (
os.walk). - (optional) tqdm – a tiny progress bar so you can see the scan move.
How it works, step by step
1. Walk the folder –
os.walk yields every sub‑folder and file, letting you examine the whole tree. 2. Hash each file – open the file in binary mode, read it chunk‑by‑chunk (e.g., 64 KB blocks) and feed those bytes into
hashlib.sha256(). This avoids loading huge files into memory. 3. Group by hash – store the resulting hash as a key in a
defaultdict(list). Every time you see the same hash, you append the new path to that list. 4. Report duplicates – after the scan, any hash with more than one path means those files are byte‑for‑byte identical. Print them out, or later add a prompt to delete the extras.
Why hashing is reliable
A SHA‑256 hash is 256 bits long; the chance of two different files sharing the same hash (a collision) is astronomically low—practically zero for everyday use. So comparing hashes is far faster than comparing every file byte‑by‑byte.
Mini‑example (core logic)
import os
import hashlib
from pathlib import Path
from collections import defaultdict
def hash_file(path: Path, chunk_size: int = 65536) -> str:
"""Return SHA‑256 hash of file contents."""
hasher = hashlib.sha256()
with path.open('rb') as f:
for chunk in iter(lambda: f.read(chunk_size), b''):
hasher.update(chunk)
return hasher.hexdigest()
def find_duplicates(root_folder: str) -> dict:
"""Scan root_folder and return dict {hash: [paths...] } for duplicates."""
hash_map = defaultdict(list)
for dirpath, _, filenames in os.walk(root_folder):
for name in filenames:
file_path = Path(dirpath) / name
try:
file_hash = hash_file(file_path)
hash_map[file_hash].append(file_path)
except (OSError, PermissionError):
# Skip files we can't read
continue
# Keep only entries with more than one file (real duplicates)
return {h: p for h, p in hash_map.items() if len(p) > 1}
# ---- demo ----
if __name__ == "__main__":
folder = input("Folder to scan: ").strip()
duplicates = find_duplicates(folder)
if not duplicates:
print("✅ No duplicates found!")
else:
print("🔎 Duplicate groups:")
for i, (h, paths) in enumerate(duplicates.items(), 1):
print(f"\nGroup {i} (hash {h[:8]}…):")
for p in paths:
print(f" {p}")
What you can add next
- Command‑line arguments with
argparse (e.g., --delete to auto‑remove all but the first copy). - Progress bar via
tqdm to keep the UI friendly for big folders. - Export the report to a CSV or JSON file for later review.
Give it a try: point the script at a cluttered directory, run it, and watch the list of duplicates appear. You’ll see how a few standard libraries can turn a messy folder into a tidy workspace in minutes.
Happy cleaning! 🚀
When Python checks a condition (the part after if, while, etc.) it needs to decide whether the statement is True or False.
You might think it only looks at the words True or False, but Python is a bit smarter – it treats many everyday values as “truthy” (meaning True) or “falsy” (meaning False) automatically.
What counts as falsy?
-
-
-
-
-
-
-
Everything else is considered truthy – even things you might not expect, like a non‑empty string
Why does this help?
Because you can write shorter, clearer code. Instead of checking the length of a list, you can just ask “does the list have something in it?”:
The same idea works for strings, numbers, and many other objects:
A handy trick: use the
Here Python evaluates
Bottom line:
- Think of falsy as “empty or nothing”.
- Anything that isn’t falsy is truthy.
- Use this shortcut to write cleaner, more pythonic code that reads almost like plain English.
Happy coding! 🎉
You might think it only looks at the words True or False, but Python is a bit smarter – it treats many everyday values as “truthy” (meaning True) or “falsy” (meaning False) automatically.
What counts as falsy?
-
0 – the number zero -
0.0 – zero as a float -
"" – an empty string, nothing between the quotes -
[] – an empty list, no items inside -
{} – an empty dictionary, no key‑value pairs -
set() – an empty set -
None – a special value that means “nothing here”Everything else is considered truthy – even things you might not expect, like a non‑empty string
"False" or a list with a single zero [0].Why does this help?
Because you can write shorter, clearer code. Instead of checking the length of a list, you can just ask “does the list have something in it?”:
my_list = [] # try changing this to ['apple']
if my_list: # works because an empty list is falsy
print("We have items!")
else:
print("The list is empty.")
The same idea works for strings, numbers, and many other objects:
name = "" # try changing this to "Alice"
if name:
print(f"Hello, {name}!")
else:
print("You didn't type a name.")
A handy trick: use the
or operator to give a default value when something is falsy.user_input = "" # imagine the user pressed Enter without typing
# If user_input is falsy (empty), use "guest" instead
username = user_input or "guest"
print(f"Welcome, {username}!")
Here Python evaluates
user_input. If it’s truthy, username gets that value; if it’s falsy, Python moves on to the right side of or and picks "guest".Bottom line:
- Think of falsy as “empty or nothing”.
- Anything that isn’t falsy is truthy.
- Use this shortcut to write cleaner, more pythonic code that reads almost like plain English.
Happy coding! 🎉
🚀 Quick One‑Sitting Project: “Terminal Quizzer” – a tiny CSV‑driven quiz game
Ever wanted a fun way to test yourself on anything from capitals to Python facts, without leaving the console? Build a terminal‑based quiz that reads questions from a simple CSV file and scores you in real time. It’s perfect for a beginner because:
* CSV (Comma‑Separated Values) is a plain‑text table format – think of an Excel sheet you can open in any editor. Python’s built‑in
* The whole script stays under 60 lines, so you can finish it in a single coffee break.
* You’ll practice file I/O, loops, randomisation, and basic functions – all core concepts for any Python developer.
How it works (plain English)
1. Create a
Example row:
2. Load the CSV with
Why it works:
3. Shuffle the list using
Why it works:
4. Ask each question with
Why it works:
5. Show the final score and optionally a simple performance message.
All of this uses only the standard library – no external packages required.
Minimal code sketch
What to try next
* Add a timer (
* Store high scores in a tiny text file to track progress over weeks.
* Expand the CSV with multiple‑choice options and let the script validate selections.
Give it a go – create a
Ever wanted a fun way to test yourself on anything from capitals to Python facts, without leaving the console? Build a terminal‑based quiz that reads questions from a simple CSV file and scores you in real time. It’s perfect for a beginner because:
* CSV (Comma‑Separated Values) is a plain‑text table format – think of an Excel sheet you can open in any editor. Python’s built‑in
csv module lets you read it line‑by‑line without any extra packages. * The whole script stays under 60 lines, so you can finish it in a single coffee break.
* You’ll practice file I/O, loops, randomisation, and basic functions – all core concepts for any Python developer.
How it works (plain English)
1. Create a
questions.csv – each row holds a question, the correct answer, and optionally a hint. Example row:
What is the capital of France?,Paris,It's called the City of Light2. Load the CSV with
csv.DictReader. This gives you a dictionary per row, so you can refer to fields by name (row["question"]). Why it works:
DictReader reads the header line, maps each column name to its value, and yields a dict for every subsequent line.3. Shuffle the list using
random.shuffle. This ensures a fresh order each run, making the quiz feel less predictable. Why it works:
shuffle rearranges the list in place; the same objects stay, only their positions change.4. Ask each question with
input(). Compare the user’s answer (case‑insensitive) to the stored answer. Keep a running score. Why it works:
input() pauses the program and returns whatever the user typed as a string; .strip().lower() normalises it for a fair comparison.5. Show the final score and optionally a simple performance message.
All of this uses only the standard library – no external packages required.
Minimal code sketch
import csv
import random
def load_questions(path: str) -> list[dict]:
"""Read CSV and return a list of question dicts."""
with open(path, newline='', encoding='utf-8') as f:
return list(csv.DictReader(f))
def ask_question(q: dict) -> bool:
"""Prompt user, return True if answer matches."""
print("\n❓", q["question"])
if q.get("hint"):
print("💡 Hint:", q["hint"])
answer = input("Your answer: ").strip().lower()
correct = q["answer"].strip().lower()
if answer == correct:
print("✅ Correct!")
return True
else:
print(f"❌ Wrong – the answer is: {q['answer']}")
return False
def run_quiz(csv_path: str):
questions = load_questions(csv_path)
random.shuffle(questions) # random order each run
score = 0
for q in questions:
if ask_question(q):
score += 1
print("\n--- Quiz finished ---")
print(f"Your score: {score}/{len(questions)}")
if score == len(questions):
print("🏆 Perfect! You're a quiz master!")
elif score > len(questions) / 2:
print("👍 Good job! Keep practicing.")
else:
print("👎 Better luck next time!")
if __name__ == "__main__":
run_quiz("questions.csv")
What to try next
* Add a timer (
time.time()) to see how fast you answer. * Store high scores in a tiny text file to track progress over weeks.
* Expand the CSV with multiple‑choice options and let the script validate selections.
Give it a go – create a
questions.csv, paste the code, run python quiz.py, and watch the learning fun unfold! 🎉👋 Hey Python newbies!
Let’s talk about functions – the building blocks that let you reuse code, keep things tidy, and make your programs smarter. Think of a function as a tiny machine: you feed it some ingredients (arguments), it does a job, and then hands you back a result (a return value).
Why use a function?
- Reuse – Write the logic once, call it many times.
- Readability – A well‑named function tells the reader what is happening without digging into details.
- Testing – Small, isolated pieces are easier to check for bugs.
The anatomy of a simple function
-
-
-
- Docstring (
-
Calling the function
When you call
print vs return – a quick bolded list
print
- Shows something on the screen right away.
- Does not give the value back to the rest of your code.
- Use it for debugging or user interaction.
return
- Sends a value back to the place where the function was called.
- Lets you store, manipulate, or combine the result later.
- Essential for building larger programs.
A tiny exercise: a calculator function
What’s happening?
1.
2. Inside the function,
3.
4. The caller stores it in
A couple of tips to keep in mind
- Naming: Use clear, lowercase names with underscores (
- Scope: Variables created inside a function are local – they don’t clash with variables outside.
- Default values: You can give a parameter a default so the caller can omit it (e.g.,
Give it a try! Write a function that tells whether a number is even or odd, call it a few times, and print the results. 🎉
Happy coding, and remember: functions make your code reusable, readable, and powerful!
Let’s talk about functions – the building blocks that let you reuse code, keep things tidy, and make your programs smarter. Think of a function as a tiny machine: you feed it some ingredients (arguments), it does a job, and then hands you back a result (a return value).
Why use a function?
- Reuse – Write the logic once, call it many times.
- Readability – A well‑named function tells the reader what is happening without digging into details.
- Testing – Small, isolated pieces are easier to check for bugs.
The anatomy of a simple function
def greet(name):
"""Return a friendly greeting for the given name."""
message = f"Hello, {name}!" # build the text
return message # give the result back
-
def – keyword that starts a function definition. -
greet – the function’s name; choose something that describes its job. -
(name) – parameters (inputs) the function expects. - Docstring (
"""…""") – a short description; tools like help(greet) will show it. -
return – sends a value out of the function. Without it, the function would give back None.Calling the function
result = greet("Ada")
print(result) # 👉 Hello, Ada!When you call
greet("Ada"), Python creates a local copy of the variable name that only exists inside the function. Once the function finishes, that local copy disappears, but the value you return stays with you (here, stored in result).print vs return – a quick bolded list
- Shows something on the screen right away.
- Does not give the value back to the rest of your code.
- Use it for debugging or user interaction.
return
- Sends a value back to the place where the function was called.
- Lets you store, manipulate, or combine the result later.
- Essential for building larger programs.
A tiny exercise: a calculator function
def add(a, b):
"""Add two numbers and give the sum back."""
return a + b # the result is sent back
# Using the function
x = 5
y = 7
sum_result = add(x, y) # sum_result now holds 12
print("The sum is:", sum_result)
What’s happening?
1.
add receives two arguments (a and b). 2. Inside the function,
a + b is evaluated. 3.
return hands that result (12) back to the caller. 4. The caller stores it in
sum_result and prints it.A couple of tips to keep in mind
- Naming: Use clear, lowercase names with underscores (
snake_case). - Scope: Variables created inside a function are local – they don’t clash with variables outside.
- Default values: You can give a parameter a default so the caller can omit it (e.g.,
def greet(name="Friend"):). Give it a try! Write a function that tells whether a number is even or odd, call it a few times, and print the results. 🎉
Happy coding, and remember: functions make your code reusable, readable, and powerful!
Ever wanted to whisper messages to a distant friend using only clicks and beeps? Build a Morse‑code translator that can turn ordinary text into the classic “· – · · – –” rhythm and back again—all in a single Python session.
What you’ll learn
- Dictionaries as fast look‑up tables (the core of the alphabet ↔ Morse mapping).
- String manipulation – looping through characters, joining lists, handling spaces.
- Optional sound – playing a short beep for a dot and a longer one for a dash (uses the built‑in
- Time delays –
Why it works
A Morse code chart is just a set of fixed pairs: each letter (or digit) maps to a pattern of dots (
When encoding, you split the input into characters, fetch each pattern, and join them with a single space (the conventional separator between letters). Decoding does the opposite: you split the Morse string on spaces, look up the reverse dictionary, and rebuild the plain text.
The sound part works because a dot is a short beep (≈0.1 s) and a dash is three times longer (≈0.3 s). By pausing a tiny amount after each element (
Sketch of the code (feel free to copy‑paste and expand)
(continued below 👇)
What you’ll learn
- Dictionaries as fast look‑up tables (the core of the alphabet ↔ Morse mapping).
- String manipulation – looping through characters, joining lists, handling spaces.
- Optional sound – playing a short beep for a dot and a longer one for a dash (uses the built‑in
winsound on Windows or simpleaudio on any platform). - Time delays –
time.sleep lets you pace the signals so they feel like real Morse.Why it works
A Morse code chart is just a set of fixed pairs: each letter (or digit) maps to a pattern of dots (
.) and dashes (-). Storing those pairs in a Python dictionary lets you retrieve the pattern in O(1) time—perfect for quick look‑ups while you iterate over a message. When encoding, you split the input into characters, fetch each pattern, and join them with a single space (the conventional separator between letters). Decoding does the opposite: you split the Morse string on spaces, look up the reverse dictionary, and rebuild the plain text.
The sound part works because a dot is a short beep (≈0.1 s) and a dash is three times longer (≈0.3 s). By pausing a tiny amount after each element (
time.sleep(0.1)) and a longer pause between letters (time.sleep(0.3)), you recreate the timing that telegraph operators relied on.Sketch of the code (feel free to copy‑paste and expand)
import time
try:
# Windows has winsound built‑in
import winsound
beep = lambda duration: winsound.Beep(750, duration) # 750 Hz tone
except ImportError:
# On other OSes use simpleaudio (install with pip install simpleaudio)
import simpleaudio as sa
def beep(duration):
freq = 750
fs = 44100
t = (duration / 1000)
samples = (sa.np.sin(2 * sa.np.pi * sa.np.arange(fs * t) * freq / fs)).astype(sa.np.float32)
sa.play_buffer((samples * 32767).astype(sa.np.int16), 1, 2, fs).wait_done()
# 1️⃣ Build the lookup tables
MORSE_CODE = {
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..',
'E': '.', 'F': '..-.', 'G': '--.', 'H': '....',
'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
'M': '--', 'N': '-.', 'O': '---', 'P': '.--.',
'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-',
'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
'Y': '-.--', 'Z': '--..',
'0': '-----', '1': '.----', '2': '..---','3': '...--',
'4': '....-', '5': '.....', '6': '-....','7': '--...',
'8': '---..', '9': '----.'
}
# Reverse lookup for decoding
REVERSE_MORSE = {v: k for k, v in MORSE_CODE.items()}
def encode(text: str) -> str:
"""Turn plain text into Morse (dots & dashes)."""
return ' '.join(MORSE_CODE.get(ch.upper(), '') for ch in text if ch != ' ')
def decode(morse: str) -> str:
"""Turn Morse back into plain text."""
return ''.join(REVERSE_MORSE.get(code, '') for code in morse.split())
def play(morse: str):
"""Audibly play Morse using beeps."""
for symbol in morse:
if symbol == '.':
beep(100) # dot: 0.1 s
elif symbol == '-':
beep(300) # dash: 0.3 s
time.sleep(0.1) # pause between parts of same letter
if symbol == ' ':
time.sleep(0.3) # extra pause between letters
# 👇 Try it out
msg = "SOS HELP"
encoded = encode(msg)
print(f"Encoded: {encoded}") # → ... --- ... .... . .-.. .--.
decoded = decode(encoded)
print(f"Decoded: {decoded}") # → SOSHELP
# Uncomment to hear it (may need simpleaudio installed)
# play(encoded)
(continued below 👇)
How to make it your own
- Add support for spaces between words by using “/” as a separator.
- Let the user choose frequency or speed via command‑line arguments (
- Store a log of sent messages in a tiny text file (practice file I/O).
- Turn it into a tiny GUI with
Give it a spin, tweak the tones, and you’ll have a functional Morse‑code tool that feels like a piece of telegraph history—all built with just a handful of Python basics. Happy coding!
- Add support for spaces between words by using “/” as a separator.
- Let the user choose frequency or speed via command‑line arguments (
argparse). - Store a log of sent messages in a tiny text file (practice file I/O).
- Turn it into a tiny GUI with
tkinter for button clicks and visual “· –” output.Give it a spin, tweak the tones, and you’ll have a functional Morse‑code tool that feels like a piece of telegraph history—all built with just a handful of Python basics. Happy coding!
What’s a set?
A set is a built‑in collection that holds unique items – duplicates are automatically removed. Think of it as a bag where every element can appear only once.
Why use a set?
- Fast membership test – asking “is this value in the collection?” is lightning quick (average O(1) time) because Python stores items in a hash table.
- Automatic deduplication – you never need to write extra loops to get rid of repeats.
How does it work?
When you add a value, Python computes a hash (a numeric fingerprint) for that value. If the fingerprint already exists, the new value is ignored. This is why only hashable objects (numbers, strings, tuples) can be members of a set.
Creating a set
Common set operations
- Add one item –
- Remove an item –
- Check membership –
- Set math – union (
Quick cheat‑sheet (bolded list)
- list – ordered, allows duplicates, slower membership (
- set – unordered, no duplicates, fast membership (
Real‑world example: filtering user input
Suppose you ask a user to type several favorite colors, separated by commas, and you want to keep only the distinct ones:
Tip: If you later need the unique items in the original order, convert back with a simple loop:
Remember:
- Use a set whenever you need “no duplicates” or “quick look‑ups”.
- You cannot store mutable types like lists or dictionaries inside a set because they aren’t hashable.
Give it a try! Play with
A set is a built‑in collection that holds unique items – duplicates are automatically removed. Think of it as a bag where every element can appear only once.
Why use a set?
- Fast membership test – asking “is this value in the collection?” is lightning quick (average O(1) time) because Python stores items in a hash table.
- Automatic deduplication – you never need to write extra loops to get rid of repeats.
How does it work?
When you add a value, Python computes a hash (a numeric fingerprint) for that value. If the fingerprint already exists, the new value is ignored. This is why only hashable objects (numbers, strings, tuples) can be members of a set.
Creating a set
# start with a list that has repeats
numbers = [1, 2, 3, 2, 4, 1, 5]
# turn it into a set – duplicates disappear
unique_numbers = set(numbers)
print(unique_numbers) # {1, 2, 3, 4, 5}
Common set operations
- Add one item –
my_set.add(item) - Remove an item –
my_set.discard(item) (no error if missing) - Check membership –
item in my_set (very fast) - Set math – union (
|), intersection (&), difference (-)Quick cheat‑sheet (bolded list)
- list – ordered, allows duplicates, slower membership (
O(n)) - set – unordered, no duplicates, fast membership (
O(1)) Real‑world example: filtering user input
Suppose you ask a user to type several favorite colors, separated by commas, and you want to keep only the distinct ones:
raw = input("Enter colors, separated by commas: ")
# split into a list, strip spaces, lower‑case for uniformity
color_list = [c.strip().lower() for c in raw.split(",")]
# use a set to drop repeats
unique_colors = set(color_list)
print("You gave", len(unique_colors), "different colors:")
print(unique_colors)Tip: If you later need the unique items in the original order, convert back with a simple loop:
ordered_unique = []
seen = set()
for c in color_list:
if c not in seen:
ordered_unique.append(c)
seen.add(c)
print(ordered_unique) # preserves the order user typed
Remember:
- Use a set whenever you need “no duplicates” or “quick look‑ups”.
- You cannot store mutable types like lists or dictionaries inside a set because they aren’t hashable.
Give it a try! Play with
set() in the Python REPL and watch duplicates vanish instantly. 🚀Hey everyone! 🎉 We’re launching a brand‑new Python series that starts from absolute zero – no prior coding experience required. Get ready to step into the world of programming together, with a friendly, supportive vibe that makes learning feel like a fun adventure. The first lesson is just around the corner, and we can’t wait to share the full roadmap with you soon! Stay tuned and get excited – your coding journey is about to begin.
🚀 Python Learning Roadmap – From Zero to Hero!
Fundamentals – Get comfortable with the language:
- Installing Python & setting up VS Code or PyCharm
- Running scripts, REPL, and basic syntax
- Variables, data types, and simple I/O
Control Flow – Direct the program’s path:
- Conditional statements (
- Looping constructs (
- Basic error handling with
Functions – Build reusable blocks:
- Defining functions, arguments, and return values
- Default & keyword arguments,
- Scope, recursion, and lambda expressions
Data Structures – Organize information efficiently:
- Lists, tuples, sets, and dictionaries
- List comprehensions & generator expressions
- Common methods, slicing, and built‑in functions
Object‑Oriented Programming (OOP) – Model real‑world concepts:
- Classes, objects, attributes, and methods
- Inheritance, polymorphism, and magic methods (
- Encapsulation and property decorators
Beyond – Level up your toolkit:
- Modules, packages, and virtual environments
- File I/O, JSON, CSV handling
- Decorators, context managers, and generators
- Introduction to testing with
Each bullet point will become one dedicated lesson, posted every 2–3 days. Get ready to write your first script, master clean code, and unleash powerful Python tricks—the journey starts now!
Fundamentals – Get comfortable with the language:
- Installing Python & setting up VS Code or PyCharm
- Running scripts, REPL, and basic syntax
- Variables, data types, and simple I/O
Control Flow – Direct the program’s path:
- Conditional statements (
if / elif / else) - Looping constructs (
while, for) and range - Basic error handling with
try / except Functions – Build reusable blocks:
- Defining functions, arguments, and return values
- Default & keyword arguments,
*args / **kwargs - Scope, recursion, and lambda expressions
Data Structures – Organize information efficiently:
- Lists, tuples, sets, and dictionaries
- List comprehensions & generator expressions
- Common methods, slicing, and built‑in functions
Object‑Oriented Programming (OOP) – Model real‑world concepts:
- Classes, objects, attributes, and methods
- Inheritance, polymorphism, and magic methods (
__init__, __str__, etc.) - Encapsulation and property decorators
Beyond – Level up your toolkit:
- Modules, packages, and virtual environments
- File I/O, JSON, CSV handling
- Decorators, context managers, and generators
- Introduction to testing with
unittest / pytest Each bullet point will become one dedicated lesson, posted every 2–3 days. Get ready to write your first script, master clean code, and unleash powerful Python tricks—the journey starts now!
❤1
Why you need Python installed – Python is an interpreter language. When you write a .py file the code is not compiled into a standalone executable; instead the Python interpreter reads the text, translates it to byte‑code and executes it on the fly. Therefore a working interpreter must be reachable from the command line (or an IDE) before any script can run.
What “installing” really does – The installer copies the interpreter binaries, the standard library, and a small set of tools (pip, IDLE, …) onto your computer. It also (optionally) registers the location of the interpreter in the system’s PATH variable so you can type
Platform‑specific notes –
Windows – the official installer asks whether to “Add Python to PATH”. Tick it, otherwise you’ll have to type the full path like
macOS – the installer bundles Python in
Linux – most distributions ship Python already. You can verify with
Step‑by‑step installation (Windows example)
1. Download the latest stable release from https://www.python.org/downloads/. Choose the Windows installer (e.g.,
2. Run the installer. At the first screen check “Add Python 3.12 to PATH” – this tells the OS to look in the interpreter’s folder automatically.
3. Click “Customize installation” if you want to select optional features (pip, documentation, test suite). Otherwise, “Install Now” works for most users.
4. After the progress bar finishes, a “Setup was successful” message appears. You can close the installer.
Verification – Open Command Prompt (⌘ + R →
You should see something like
Running your first script
A script is just a plain text file with the extension
Create the file
1. Open any text editor (Notepad, VS Code, Sublime…).
2. Type the code shown below.
3. Save the file as
What each line does
-
-
-
-
-
-
-
Running it
Open a terminal (Command Prompt on Windows, Terminal on macOS/Linux), navigate to the folder containing
(continued below 👇)
What “installing” really does – The installer copies the interpreter binaries, the standard library, and a small set of tools (pip, IDLE, …) onto your computer. It also (optionally) registers the location of the interpreter in the system’s PATH variable so you can type
python anywhere in a terminal and have the OS locate the right executable.Platform‑specific notes –
Windows – the official installer asks whether to “Add Python to PATH”. Tick it, otherwise you’ll have to type the full path like
C:\Python311\python.exe. macOS – the installer bundles Python in
/Library/Frameworks/Python.framework/Versions/3.x. Adding /usr/local/bin (a symlink created by the installer) to PATH is enough. Linux – most distributions ship Python already. You can verify with
python3 --version. If you need a newer version, use the package manager (apt, dnf, pacman, …) or download a binary from python.org.Step‑by‑step installation (Windows example)
1. Download the latest stable release from https://www.python.org/downloads/. Choose the Windows installer (e.g.,
python-3.12.0-amd64.exe). 2. Run the installer. At the first screen check “Add Python 3.12 to PATH” – this tells the OS to look in the interpreter’s folder automatically.
3. Click “Customize installation” if you want to select optional features (pip, documentation, test suite). Otherwise, “Install Now” works for most users.
4. After the progress bar finishes, a “Setup was successful” message appears. You can close the installer.
Verification – Open Command Prompt (⌘ + R →
cmd) and type:python --version
You should see something like
Python 3.12.0. If you get “'python' is not recognized…”, the PATH wasn’t set; you can add the interpreter folder manually in System → Advanced system settings → Environment Variables.Running your first script
A script is just a plain text file with the extension
.py. The interpreter reads it line by line.Create the file
1. Open any text editor (Notepad, VS Code, Sublime…).
2. Type the code shown below.
3. Save the file as
hello.py on your Desktop (or any folder you like).# hello.py
# This is a minimal Python program.
# It prints a greeting to the console.
def main():
"""Entry point of the script."""
greeting = "Hello, World!"
print(greeting) # print() sends text to the standard output (your terminal)
if __name__ == "__main__":
# When the file is executed directly, __name__ becomes "__main__".
# This guard prevents the code from running if the file is imported as a module.
main()
What each line does
-
# hello.py – a comment; ignored by the interpreter, used for human readers. -
def main(): – defines a function called main. Functions group code so it can be reused or called later. -
"""Entry point of the script.""" – a docstring; a special comment that describes the function. -
greeting = "Hello, World!" – creates a variable named greeting and stores the text. -
print(greeting) – built‑in function that writes the variable’s value to the console. -
if __name__ == "__main__": – a conditional that checks whether the file is being run directly (true) or imported (false). -
main() – calls the main function, starting the program’s execution.Running it
Open a terminal (Command Prompt on Windows, Terminal on macOS/Linux), navigate to the folder containing
hello.py:(continued below 👇)
Python.org
Download Python
The official home of the Python Programming Language
cd %USERPROFILE%\Desktop
Then execute:
python hello.py
You should see:
Hello, World!
Why this works – The
python command launches the interpreter, which reads hello.py, compiles it to byte‑code, and runs the top‑level statements. The if __name__ == "__main__": block ensures that main() runs only when you start the script, not when another script does import hello.Quick sanity checklist
- Python in PATH?
python --version works anywhere. - File saved with .py extension? Otherwise the OS won’t know it’s Python code.
- Correct working directory?
cd to the folder before running, or give the full path: python C:\Users\Me\Desktop\hello.py. - Using the right command? On some Linux/macOS setups you may need
python3 instead of python.You’re now ready to explore variables, control flow, and the massive Python ecosystem. Happy coding!
Which line in a Python script ensures that code runs only when the file is executed directly, not when imported?
Anonymous Quiz
67%
if __name__ == "__main__":
0%
if __name__ == "main":
0%
if __name__ == "__file__":
33%
if __name__ == "module"
print() is the built‑in function Python uses to send text to the standard output stream (normally the console you run your program in).
When you call
Why does it add a newline automatically?
The
Key arguments of
- sep – string placed between each value (default space).
- end – string placed after the last value (default newline).
- file – where to send the output (default
- flush – whether to force the buffer to write immediately.
Comments let you embed human‑readable explanations in your code.
Python ignores everything after a
- Describing why you wrote a piece of code.
- Leaving TODO notes for future work.
- Temporarily disabling code while testing.
Python has two comment styles:
1. Single‑line comment – starts with
2. Multi‑line comment – technically a string literal that isn’t assigned to any name, usually written with triple quotes
Putting it together – a complete example
Walk‑through of each line
1.
2.
3.
4.
5. The two
6. The
Why comments are ignored – When Python parses a file, it tokenises the source. Anything that matches the comment pattern (
Quick comparison
(continued below 👇)
When you call
print() Python takes the objects you give it, turns each into a string, joins them together, adds a line‑break, and writes the result to that stream.Why does it add a newline automatically?
The
print() signature includes end='\n'. That means after printing the supplied values it appends the end string, which defaults to a newline character. You can change it to anything you like (even an empty string) to control what appears after the output.Key arguments of
print() - sep – string placed between each value (default space).
- end – string placed after the last value (default newline).
- file – where to send the output (default
sys.stdout). - flush – whether to force the buffer to write immediately.
Comments let you embed human‑readable explanations in your code.
Python ignores everything after a
# on a line, so the interpreter never executes it. This makes comments perfect for:- Describing why you wrote a piece of code.
- Leaving TODO notes for future work.
- Temporarily disabling code while testing.
Python has two comment styles:
1. Single‑line comment – starts with
#. Everything to the right of it on the same line is ignored. 2. Multi‑line comment – technically a string literal that isn’t assigned to any name, usually written with triple quotes
''' … ''' or """ … """. It’s ignored like a comment, but it also serves as a docstring when placed as the first statement in a module, class, or function.Putting it together – a complete example
# This script demonstrates print() and comments
# Define a variable to hold our greeting
greeting = "Hello, world!"
# Basic print – adds a newline automatically
print(greeting) # prints: Hello, world!
# Using sep to customize separation between arguments
print("Sum:", 2, "+", 3, "=", 2+3, sep=" ") # prints: Sum: 2 + 3 = 5
# Changing the end string so the next print continues on the same line
print("First part...", end=" *** ") # no newline, custom end
print("second part") # continues after the *** marker
# Directing output to a file instead of the console
with open("output.txt", "w") as f:
print("This goes into a file.", file=f) # writes the line to output.txt
Walk‑through of each line
1.
# This script demonstrates print() and comments – a single‑line comment explaining the purpose of the file. 2.
greeting = "Hello, world!" – stores a string in a variable; the comment above tells you why we have this variable. 3.
print(greeting) – prints the variable’s value and automatically appends a newline because end defaults to '\n'. 4.
print("Sum:", 2, "+", 3, "=", 2+3, sep=" ") – shows how sep changes the separator between items (here a single space). The expression 2+3 is evaluated first, then converted to a string. 5. The two
print() calls with end=" *** " demonstrate overriding the default newline. The first call ends with *** instead of \n, so the next print continues on the same line. 6. The
with open(..., "w") as f: block opens a file for writing. Inside it, print(..., file=f) sends the text to the file rather than the console. This illustrates the file argument.Why comments are ignored – When Python parses a file, it tokenises the source. Anything that matches the comment pattern (
# ... or an unassigned triple‑quoted string) is stripped out before the abstract syntax tree is built. Therefore comments have zero runtime cost.Quick comparison
(continued below 👇)
print() vs. comments
- Purpose: output data vs. annotate code
- Runtime effect: produces visible result vs. none
- Syntax: function call vs.
- Customization: many arguments (sep, end, file) vs. none
- Purpose: output data vs. annotate code
- Runtime effect: produces visible result vs. none
- Syntax: function call vs.
# or ''' … ''' - Customization: many arguments (sep, end, file) vs. none
Which argument of `print()` controls what appears after the printed text?
Anonymous Quiz
0%
The separator between items
100%
The string appended after the output
0%
The target file for output
0%
Whether to flush the buffer
📘 Day 3: Variables and basic data types (int, float, str, bool)
Variables are names that point to values stored in memory. When you write
Because Python is dynamically typed, the type of the value is attached to the object, not to the variable name. You can later re‑assign the same name to a completely different type (
Naming rules – a variable name
- must start with a letter (
- can contain letters, digits, or underscores after the first character
- is case‑sensitive (
- must not be a reserved keyword (
Basic data types you’ll meet first:
int – whole numbers, unlimited precision (
float – real numbers with a decimal point or exponent (
str – text, enclosed in single, double, or triple quotes (
bool – logical truth values, only
All four are immutable: once created, their contents cannot change. If you “modify” a variable, Python actually creates a new object and re‑binds the name to it.
Why does
When you call
Common operations
- Arithmetic (
- String concatenation uses
- Boolean logic (
Here is a complete, runnable example that touches every point:
Line‑by‑line walk‑through
(continued below 👇)
Variables are names that point to values stored in memory. When you write
age = 25 Python creates an object representing the integer 25, then stores a reference to that object in the name age. Because Python is dynamically typed, the type of the value is attached to the object, not to the variable name. You can later re‑assign the same name to a completely different type (
age = "twenty‑five"), and Python will happily accept it.Naming rules – a variable name
- must start with a letter (
a‑z, A‑Z) or an underscore (_) - can contain letters, digits, or underscores after the first character
- is case‑sensitive (
score ≠ Score) - must not be a reserved keyword (
def, for, while, …)Basic data types you’ll meet first:
int – whole numbers, unlimited precision (
-3, 0, 42) float – real numbers with a decimal point or exponent (
3.14, 2e-5) str – text, enclosed in single, double, or triple quotes (
'hello', "world") bool – logical truth values, only
True or FalseAll four are immutable: once created, their contents cannot change. If you “modify” a variable, Python actually creates a new object and re‑binds the name to it.
Why does
type() work?When you call
type(x), Python looks at the object that x references and returns its class (int, float, str, bool). This is why the same name can give different results after reassignment – the underlying object changed, not the variable itself.Common operations
- Arithmetic (
+, -, *, /) works with int and float. Mixing the two automatically promotes the result to float.- String concatenation uses
+ ('Hi' + '!'). To combine numbers with strings you must convert the number (str(5)).- Boolean logic (
and, or, not) works with bool. In numeric contexts True behaves like 1 and False like 0.Here is a complete, runnable example that touches every point:
# 1️⃣ Assign different types to descriptive variable names
age = 29 # int: whole number of years
height = 1.73 # float: meters, includes a decimal
greeting = "Hello, world!" # str: text data
is_student = True # bool: logical flag
# 2️⃣ Inspect the types
print("type(age) ->", type(age))
print("type(height) ->", type(height))
print("type(greeting) ->", type(greeting))
print("type(is_student)->", type(is_student))
# 3️⃣ Simple operations showing type interaction
next_year_age = age + 1 # int + int → int
half_height = height / 2 # float / int → float
welcome_msg = greeting + " 👋" # str + str → str
can_vote = (age >= 18) and is_student # bool expression → bool
# 4️⃣ Display the results
print("\n--- Calculations ---")
print("next_year_age =", next_year_age, "(type:", type(next_year_age), ")")
print("half_height =", half_height, "(type:", type(half_height), ")")
print("welcome_msg =", welcome_msg, "(type:", type(welcome_msg), ")")
print("can_vote =", can_vote, "(type:", type(can_vote), ")")
Line‑by‑line walk‑through
(continued below 👇)
1. Comments (
2.
3.
4. Arithmetic:
5. String concatenation:
6. Boolean logic:
7. The final
By experimenting with this script—changing values, swapping types, adding more operations—you’ll see why Python’s dynamic typing feels flexible yet predictable: the objects carry their type, and the language’s operators know how to act on each type.
# ...) explain each assignment – they are ignored by Python. 2.
age = 29 creates an int object 29 and binds the name age to it. The same happens for the other three variables, each with its own type. 3.
type(variable) returns the class of the object, letting us confirm the stored type. 4. Arithmetic:
age + 1 adds two integers → a new integer. height / 2 mixes float and int; Python converts the int to float before division, so the result is a float. 5. String concatenation:
greeting + " 👋" joins two strings, producing a new str. 6. Boolean logic:
(age >= 18) evaluates to True (a bool). and is_student combines it with another bool, yielding the final bool stored in can_vote. 7. The final
print statements show both the values and their types, confirming how Python dynamically handles each operation.By experimenting with this script—changing values, swapping types, adding more operations—you’ll see why Python’s dynamic typing feels flexible yet predictable: the objects carry their type, and the language’s operators know how to act on each type.
Which of the following statements is true about Python variables and basic data types?
Anonymous Quiz
0%
A variable’s type is fixed at declaration
50%
A variable can be reassigned to a different type
0%
Variables must be declared with a type keyword
50%
Booleans are stored as strings
📘 Day 4: Strings: indexing, slicing, and common string methods
Strings in Python are immutable sequences of Unicode characters. Think of a string as a row of boxes, each holding one character, with a fixed order that never changes once the string is created. Because of this ordering, Python lets you address individual characters and extract sub‑strings using indexing and slicing.
Indexing
- Every character has a zero‑based position: the first character is index 0, the second is 1, and so on.
- Python also supports negative indices: -1 refers to the last character, -2 to the one before that, etc.
- Indexing returns a new string containing exactly one character.
Why it works: Under the hood, a string object stores its characters in a contiguous memory block. When you ask for
Slicing
- A slice is written
-
-
- The result is another string that contains the selected characters in order.
Why it works: Python builds the slice by iterating from
Common string methods – these are functions bound to a string object that return a new string (the original stays unchanged). Some frequently used ones:
-
-
-
-
-
Each method works by scanning the original string, applying its rule, and constructing a brand‑new string object. Because strings are immutable, this design avoids accidental side‑effects.
Putting it all together – a complete example
(continued below 👇)
Strings in Python are immutable sequences of Unicode characters. Think of a string as a row of boxes, each holding one character, with a fixed order that never changes once the string is created. Because of this ordering, Python lets you address individual characters and extract sub‑strings using indexing and slicing.
Indexing
- Every character has a zero‑based position: the first character is index 0, the second is 1, and so on.
- Python also supports negative indices: -1 refers to the last character, -2 to the one before that, etc.
- Indexing returns a new string containing exactly one character.
Why it works: Under the hood, a string object stores its characters in a contiguous memory block. When you ask for
s[i], Python calculates the memory offset base_address + i * size_of_character (handling negative i by adding the length). It then creates a new 1‑character string from that location.Slicing
- A slice is written
s[start:stop:step]. -
start is inclusive, stop is exclusive. If omitted, they default to the beginning (0) and the end (len(s)), respectively. -
step controls the stride; a negative step walks the string backwards. - The result is another string that contains the selected characters in order.
Why it works: Python builds the slice by iterating from
start to stop (excluding) using the given step. For each position it fetches the character (just like indexing) and appends it to a new buffer, which becomes the sliced string.Common string methods – these are functions bound to a string object that return a new string (the original stays unchanged). Some frequently used ones:
-
.upper() – returns a copy with all letters converted to uppercase. -
.lower() – returns a copy with all letters converted to lowercase. -
.replace(old, new, count=-1) – substitutes occurrences of old with new; count limits replacements. -
.split(sep=None, maxsplit=-1) – breaks the string into a list of substrings based on a separator. -
.strip(chars=None) – removes leading and trailing characters (whitespace by default). Each method works by scanning the original string, applying its rule, and constructing a brand‑new string object. Because strings are immutable, this design avoids accidental side‑effects.
Putting it all together – a complete example
# Demo: indexing, slicing, and three common methods
text = "Hello, World!" # original immutable string
# Indexing
first_char = text[0] # 'H' – start of the string
last_char = text[-1] # '!' – end of the string
# Slicing
sub = text[7:12] # 'World' – start at 7, stop before 12
reverse = text[::-1] # '!dlroW ,olleH' – step -1 walks backwards
# Methods
upper = text.upper() # 'HELLO, WORLD!'
replaced = text.replace("World", "Python") # 'Hello, Python!'
# Show everything
print("Original :", text)
print("First char:", first_char)
print("Last char :", last_char)
print("Slice [7:12]:", sub)
print("Reversed :", reverse)
print("Uppercase :", upper)
print("Replaced :", replaced)
(continued below 👇)