Python Programming
40 subscribers
5 photos
2 links
🐍 Python Programming | Code. Learn. Grow.

Welcome to Python Programming — your go-to Telegram community for mastering Python, from basics to advanced!
Download Telegram
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 (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 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 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?
- 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 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 Light

2. 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

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

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

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 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 (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

# 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 (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 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 👇)
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 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. # or ''' … '''
- Customization: many arguments (sep, end, file) vs. none
📘 Day 3: Variables and basic data types (int, float, str, bool)

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 False

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 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 (# ...) 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.