Hey Python explorers! 🌟 Ever wish you had a tiny, always‑ready to‑go to‑do list right in your terminal? Let’s build a Command‑line Todo Manager you can finish in one sitting. It’s perfect for beginners because it leans on only the standard library plus one optional, lightweight third‑party helper for nice tables.
What the app does
- Add a task with a short description and a priority (1 = high, 5 = low).
- Show all pending tasks, nicely ordered by priority and creation time.
- Mark a task as done, which moves it out of the active list.
- Persist everything between runs so you never lose a note.
Why it works
-
-
- Sorting is just a one‑liner:
- If you want a prettier table,
Sketch of the code
How to run it
(continued below 👇)
What the app does
- Add a task with a short description and a priority (1 = high, 5 = low).
- Show all pending tasks, nicely ordered by priority and creation time.
- Mark a task as done, which moves it out of the active list.
- Persist everything between runs so you never lose a note.
Why it works
-
shelve behaves like a dictionary that lives on disk. When you assign db[task_id] = task_dict, Python automatically pickles (serializes) the object and writes it to a file. The next time you open the shelf you get the same data back – no manual file handling needed. -
datetime gives us timestamps. By storing datetime.now() when a task is created we can later sort tasks chronologically, and the strftime method lets us turn those timestamps into human‑readable strings. - Sorting is just a one‑liner:
sorted(tasks, key=lambda t: (t['priority'], t['created'])). The key function tells Python how to compare items, so higher‑priority (lower number) tasks appear first, and ties are broken by the older entry. - If you want a prettier table,
tabulate (install with pip install tabulate) turns a list of dicts into an aligned grid without you writing any formatting code.Sketch of the code
import shelve
from datetime import datetime
DB_NAME = 'todos.db' # shelf file on disk
DATE_FMT = '%Y-%m-%d %H:%M' # how dates appear to the user
def add_task(desc: str, priority: int = 3):
"""Create a new task and store it."""
with shelve.open(DB_NAME) as db:
task_id = str(int(time.time() * 1000)) # simple unique key
db[task_id] = {
'desc': desc,
'priority': priority,
'created': datetime.now(),
'done': False
}
print(f'✅ Task added with ID {task_id}')
def list_tasks():
"""Show all pending tasks, sorted by priority then date."""
with shelve.open(DB_NAME) as db:
tasks = [v | {'id': k} for k, v in db.items() if not v['done']]
tasks.sort(key=lambda t: (t['priority'], t['created']))
# optional pretty table
try:
from tabulate import tabulate
table = tabulate(
[[t['id'], t['desc'], t['priority'], t['created'].strftime(DATE_FMT)]
for t in tasks],
headers=['ID', 'Description', 'Prio', 'Created'],
tablefmt='simple')
print(table)
except ImportError:
for t in tasks:
print(f"{t['id']}: [{t['priority']}] {t['desc']} (added {t['created']:{DATE_FMT}})")
def complete_task(task_id: str):
"""Mark a task as done."""
with shelve.open(DB_NAME, writeback=True) as db:
if task_id in db:
db[task_id]['done'] = True
print(f'✔️ Task {task_id} completed!')
else:
print('❌ No such task.')
# ----------------------------------------------------------------------
# Quick interactive demo (run the file and follow the prompts)
if __name__ == '__main__':
import time
while True:
cmd = input('\n[t] Add [l] List [c] Complete [q] Quit > ').strip().lower()
if cmd == 't':
d = input('Description: ')
p = int(input('Priority (1‑5, 1=high): ') or 3)
add_task(d, p)
elif cmd == 'l':
list_tasks()
elif cmd == 'c':
tid = input('Task ID to finish: ')
complete_task(tid)
elif cmd == 'q':
break
How to run it
(continued below 👇)
1. Save the script as
2. (Optional)
3. Run
Why you’ll love it
- Instant payoff – add a task, see it appear, mark it done.
- Learn core tools –
- Expandable – later you could add due dates, tags, or even a tiny web UI with Flask.
Give it a try, tweak the priority scale, or sprinkle in colors with
todo.py. 2. (Optional)
pip install tabulate for a nice table view. 3. Run
python todo.py and start adding tasks. Your list lives in todos.db and will be there next time you launch the program.Why you’ll love it
- Instant payoff – add a task, see it appear, mark it done.
- Learn core tools –
shelve for persistence, datetime for timestamps, list sorting, and a glimpse of third‑party packaging. - Expandable – later you could add due dates, tags, or even a tiny web UI with Flask.
Give it a try, tweak the priority scale, or sprinkle in colors with
colorama. In just one coffee break you’ll have a fully functional, persistent to‑do list that lives in the terminal! 🚀❤1
What’s the difference between a “copy” and a “reference” in Python?
When you write
Why does this happen?
Python stores objects (like lists, dictionaries, strings) somewhere in memory and gives each object a unique ID. Variables are just labels that point to those IDs. Assigning a variable to another variable copies the label, not the underlying data.
How to make a true copy?
Use one of the following methods so the new variable gets its own list (its own ID).
Quick ways to copy a list
- Slice syntax –
-
-
- Comprehension –
When does a shallow copy still share data?
If the list contains other mutable objects (like another list), a shallow copy copies only the outer list’s references. The inner objects are still shared.
To completely separate nested structures, use a deep copy:
Key take‑aways (bolded list)
- Reference = another name for the same object → changes affect all names.
- Shallow copy = new container, but inner items are still shared.
- Deep copy = completely independent copy, even for nested objects.
Tip for beginners: Whenever you’re about to modify a list that you also need in its original form later, make a copy first. It saves you from those puzzling bugs where data changes “by magic”.
When you write
new_list = old_list, you’re not making a fresh list – you’re just giving the same list another name. Both names point to the exact same object in memory. If you change the list through either name, the change shows up everywhere.Why does this happen?
Python stores objects (like lists, dictionaries, strings) somewhere in memory and gives each object a unique ID. Variables are just labels that point to those IDs. Assigning a variable to another variable copies the label, not the underlying data.
original = [1, 2, 3] # create a list
alias = original # alias points to the same list
alias.append(4) # modify through the alias
print(original) # 👉 [1, 2, 3, 4] – the original changed!
print(id(original), id(alias)) # 👉 same number, same object
How to make a true copy?
Use one of the following methods so the new variable gets its own list (its own ID).
Quick ways to copy a list
- Slice syntax –
copy = original[:]-
list() constructor – copy = list(original)-
copy module – import copy; copy = copy.copy(original) (shallow) - Comprehension –
copy = [x for x in original]original = [1, 2, 3]
shallow_copy = original[:] # slice copy
shallow_copy.append(5)
print("original :", original) # 👉 [1, 2, 3] – untouched
print("shallow_copy :", shallow_copy) # 👉 [1, 2, 3, 5]
print(id(original), id(shallow_copy)) # 👉 different numbers
When does a shallow copy still share data?
If the list contains other mutable objects (like another list), a shallow copy copies only the outer list’s references. The inner objects are still shared.
nested = [[1, 2], [3, 4]]
shallow = nested[:]
shallow[0].append(99) # modify inner list
print("nested :", nested) # 👉 [[1, 2, 99], [3, 4]] – changed!
print("shallow :", shallow) # 👉 same change
To completely separate nested structures, use a deep copy:
import copy
deep = copy.deepcopy(nested)
deep[0].append(100)
print("nested :", nested) # 👉 [[1, 2, 99], [3, 4]]
print("deep :", deep) # 👉 [[1, 2, 99, 100], [3, 4]]
Key take‑aways (bolded list)
- Reference = another name for the same object → changes affect all names.
- Shallow copy = new container, but inner items are still shared.
- Deep copy = completely independent copy, even for nested objects.
Tip for beginners: Whenever you’re about to modify a list that you also need in its original form later, make a copy first. It saves you from those puzzling bugs where data changes “by magic”.
❤1
Idea: Build a tiny command‑line journal that lets you add, list, and search personal entries, all saved in a single JSON file. You’ll get a useful “digital diary” you can open from any terminal, and you’ll practice file handling, data serialization, and working with dates.
Why it’s cool:
- Instantly useful – you can start recording thoughts, ideas, or daily logs right away.
- One‑file storage – JSON turns a Python dictionary into readable text, so you can peek at the file with any editor.
- No extra dependencies – only the standard library (
How it works, step by step
1. Data model – each entry is a dictionary with two keys:
-
-
All entries live inside a list stored under the top‑level key
2. Loading & saving – when the program starts it tries to read the JSON file (
- If the file is missing or empty, we start with
-
3. Adding an entry – we prompt the user with
- The current time is fetched with
- A new dict is appended to the
4. Listing entries – we loop over the stored list and print each timestamp followed by the note.
- Using
5. Searching – the user types a keyword; we filter entries whose
- This shows how to filter data without extra libraries.
6. Simple menu – a
Key concepts you’ll see in the code
- File I/O (
-
-
- Functions – keep the code tidy (
- Simple error handling –
Mini‑example (core part only)
(continued below 👇)
Why it’s cool:
- Instantly useful – you can start recording thoughts, ideas, or daily logs right away.
- One‑file storage – JSON turns a Python dictionary into readable text, so you can peek at the file with any editor.
- No extra dependencies – only the standard library (
json, datetime, os), perfect for beginners. How it works, step by step
1. Data model – each entry is a dictionary with two keys:
-
"timestamp" – a string like 2026‑10‑03 14:22 generated by datetime.now().strftime(...). -
"text" – the raw note you typed. All entries live inside a list stored under the top‑level key
"entries" in the JSON file.2. Loading & saving – when the program starts it tries to read the JSON file (
journal.json). - If the file is missing or empty, we start with
{"entries": []}. -
json.load() parses the text into a Python dict; json.dump() writes the updated dict back, with indent=2 for readability.3. Adding an entry – we prompt the user with
input("Your note: "). - The current time is fetched with
datetime.now(). - A new dict is appended to the
"entries" list, then we immediately write the file so nothing is lost.4. Listing entries – we loop over the stored list and print each timestamp followed by the note.
- Using
enumerate() (still allowed) gives us a simple numeric index, but the core idea is just iterating a list.5. Searching – the user types a keyword; we filter entries whose
"text" contains that substring (case‑insensitive) using a list comprehension. - This shows how to filter data without extra libraries.
6. Simple menu – a
while True loop prints options ([A]dd, [L]ist, [S]earch, [Q]uit) and reacts to the first character of the input, keeping the program interactive without any GUI.Key concepts you’ll see in the code
- File I/O (
open, with statement) – guarantees the file is closed automatically. -
json module – turns Python objects into text and back, making persistence easy. -
datetime formatting – human‑readable timestamps, useful for sorting or later analysis. - Functions – keep the code tidy (
load_journal(), save_journal(), add_entry(), …). - Simple error handling –
try/except around json.load() to handle a brand‑new file.Mini‑example (core part only)
(continued below 👇)
import json, os
from datetime import datetime
JOURNAL_FILE = "journal.json"
def load_journal():
if not os.path.exists(JOURNAL_FILE):
return {"entries": []}
with open(JOURNAL_FILE, "r", encoding="utf-8") as f:
try:
return json.load(f)
except json.JSONDecodeError:
return {"entries": []}
def save_journal(data):
with open(JOURNAL_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
def add_entry():
note = input("🖊️ Your note: ").strip()
if not note:
print("❗ Nothing written, skipping.")
return
entry = {
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M"),
"text": note
}
journal = load_journal()
journal["entries"].append(entry)
save_journal(journal)
print("✅ Entry saved!")
def list_entries():
journal = load_journal()
for i, e in enumerate(journal["entries"], 1):
print(f"{i}. [{e['timestamp']}] {e['text']}")
def search_entries():
term = input("🔍 Search keyword: ").lower()
journal = load_journal()
matches = [e for e in journal["entries"] if term in e["text"].lower()]
for e in matches:
print(f"[{e['timestamp']}] {e['text']}")
# ---- simple interactive loop ----
while True:
choice = input("\n[A]dd [L]ist [S]earch [Q]uit: ").strip().lower()
if choice == "a":
add_entry()
elif choice == "l":
list_entries()
elif choice == "s":
search_entries()
elif choice == "q":
print("👋 Bye!")
break
else:
print("❓ Unknown option.")
Run the script, type
a to add a note, l to see everything, or s to hunt for a keyword. All data lives safely in journal.json, and you can open that file any time to back it up or migrate it.Next steps (optional)
- Add a
delete option (remove by index). - Sort entries chronologically when listing.
- Export to a plain‑text markdown file for easy reading.
Give it a try – a few minutes of coding, and you’ll have a personal digital journal you control completely!
❤1
Why Python’s default arguments can be sneaky
When you write a function, you can give its parameters a default value so callers don’t have to supply every argument:
That works fine for immutable objects like numbers or strings.
But if you use a mutable object – e.g. a list or a dictionary – as the default, something unexpected can happen.
What “mutable” means
- Mutable objects can be changed in place (you can add, remove or alter items without creating a new object).
- Immutable objects cannot be changed after they’re created (ints, floats, strings, tuples).
Because lists and dictionaries are mutable, they can keep the changes you make between different calls to the same function.
The hidden trap
You might think each call starts with an empty list, but Python does something different:
Why?
The default value
The safe pattern
To get a fresh list every time, use
Now each call behaves as you expect:
Quick checklist for beginners
- Never use a mutable object (
- Use
- This rule also applies to default arguments in class constructors (
By following this simple habit, you’ll avoid a whole class of subtle bugs that can be hard to track down later. Happy coding!
When you write a function, you can give its parameters a default value so callers don’t have to supply every argument:
def greet(name="World"):
print(f"Hello, {name}!")
That works fine for immutable objects like numbers or strings.
But if you use a mutable object – e.g. a list or a dictionary – as the default, something unexpected can happen.
What “mutable” means
- Mutable objects can be changed in place (you can add, remove or alter items without creating a new object).
- Immutable objects cannot be changed after they’re created (ints, floats, strings, tuples).
Because lists and dictionaries are mutable, they can keep the changes you make between different calls to the same function.
The hidden trap
def add_item(item, collection=[]):
collection.append(item)
return collection
You might think each call starts with an empty list, but Python does something different:
print(add_item(1)) # → [1]
print(add_item(2)) # → [1, 2] <-- the list remembered the previous call!
print(add_item(3)) # → [1, 2, 3]
Why?
The default value
[] is created once, when the function is defined, not each time it runs. The same list object is then reused for every call that doesn’t provide its own collection.The safe pattern
To get a fresh list every time, use
None as the sentinel default and create the list inside the function:def add_item(item, collection=None):
if collection is None: # No list was passed, so make a new one
collection = [] # ← a brand‑new empty list
collection.append(item)
return collection
Now each call behaves as you expect:
print(add_item(1)) # → [1]
print(add_item(2)) # → [2]
print(add_item(3, ['a'])) # → ['a', 3] (you can still pass your own list)
Quick checklist for beginners
- Never use a mutable object (
list, dict, set) as a default value. - Use
None (or another immutable sentinel) as the default, then create the mutable object inside the function. - This rule also applies to default arguments in class constructors (
__init__) and any other callable.By following this simple habit, you’ll avoid a whole class of subtle bugs that can be hard to track down later. Happy coding!
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"