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
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.
📘 Day 4: Strings: indexing, slicing, and common string methods

Strings in Python are immutable sequences of Unicode characters. Think of a string as a row of boxes, each holding one character, with a fixed order that never changes once the string is created. Because of this ordering, Python lets you address individual characters and extract sub‑strings using indexing and slicing.

Indexing
- Every character has a zero‑based position: the first character is index 0, the second is 1, and so on.
- Python also supports negative indices: -1 refers to the last character, -2 to the one before that, etc.
- Indexing returns a new string containing exactly one character.

Why it works: Under the hood, a string object stores its characters in a contiguous memory block. When you ask for s[i], Python calculates the memory offset base_address + i * size_of_character (handling negative i by adding the length). It then creates a new 1‑character string from that location.

Slicing
- A slice is written s[start:stop:step].
- start is inclusive, stop is exclusive. If omitted, they default to the beginning (0) and the end (len(s)), respectively.
- step controls the stride; a negative step walks the string backwards.
- The result is another string that contains the selected characters in order.

Why it works: Python builds the slice by iterating from start to stop (excluding) using the given step. For each position it fetches the character (just like indexing) and appends it to a new buffer, which becomes the sliced string.

Common string methods – these are functions bound to a string object that return a new string (the original stays unchanged). Some frequently used ones:

- .upper() – returns a copy with all letters converted to uppercase.
- .lower() – returns a copy with all letters converted to lowercase.
- .replace(old, new, count=-1) – substitutes occurrences of old with new; count limits replacements.
- .split(sep=None, maxsplit=-1) – breaks the string into a list of substrings based on a separator.
- .strip(chars=None) – removes leading and trailing characters (whitespace by default).

Each method works by scanning the original string, applying its rule, and constructing a brand‑new string object. Because strings are immutable, this design avoids accidental side‑effects.

Putting it all together – a complete example

# Demo: indexing, slicing, and three common methods
text = "Hello, World!" # original immutable string

# Indexing
first_char = text[0] # 'H' – start of the string
last_char = text[-1] # '!' – end of the string

# Slicing
sub = text[7:12] # 'World' – start at 7, stop before 12
reverse = text[::-1] # '!dlroW ,olleH' – step -1 walks backwards

# Methods
upper = text.upper() # 'HELLO, WORLD!'
replaced = text.replace("World", "Python") # 'Hello, Python!'

# Show everything
print("Original :", text)
print("First char:", first_char)
print("Last char :", last_char)
print("Slice [7:12]:", sub)
print("Reversed :", reverse)
print("Uppercase :", upper)
print("Replaced :", replaced)


(continued below 👇)
Walk‑through of the code
1. text = "Hello, World!" creates the original string object.
2. text[0] and text[-1] fetch single characters using positive and negative indices.
3. text[7:12] extracts characters from position 7 up to—but not including—position 12, producing "World".
4. text[::-1] uses a step of -1; start and stop default to the string’s bounds, so Python walks from the end to the beginning, yielding the reversed string.
5. text.upper() iterates over every character, converting alphabetic ones to uppercase, and assembles a new string.
6. text.replace("World", "Python") scans for the exact substring "World" and swaps it with "Python", leaving the rest untouched.
7. The print statements display each result, confirming that the original text never changed.

Understanding how these operations work—offset calculation for indexing, iteration for slicing, and construction of new buffers for methods—gives you a solid mental model. You’ll be able to predict edge cases (e.g., out‑of‑range indices raise IndexError, slices that exceed bounds are simply clipped) and write more efficient, bug‑free string manipulations.
What does the slice expression `s[2:5]` return when `s = "abcdef"`?
Anonymous Quiz
0%
"ab"
100%
"cde"
0%
"cdef"
0%
"bcd"
📘 Day 5: f-strings and string formatting

What are f‑strings?
In Python, formatted string literals (commonly called f‑strings) let you embed Python expressions directly inside string literals, using a minimal and readable syntax. They were introduced in Python 3.6 to replace older formatting methods (% operator and str.format) with something that feels natural to write and fast to execute.

Why do they work?
When the Python interpreter sees a string that starts with the letter f (or F), it parses the content looking for pairs of curly braces {}. Anything inside those braces is treated as a regular Python expression. At runtime, the expression is evaluated, converted to a string (using __format__ if a format spec is provided), and the result replaces the braces in the final output. Because the evaluation happens while the string is being built, you can use variables, function calls, or even complex expressions without any extra concatenation.

Basic syntax

name = "Ada"
age = 28
msg = f"Hello, {name}! You are {age} years old."


- f before the opening quote tells Python to treat this as an f‑string.
- {name} and {age} are replacement fields. The interpreter looks up the current value of those variables and injects them.
- The surrounding text (Hello, , ! You are , years old.) is left untouched.

How is it different from older methods?

% operator – needs a separate tuple or dict, can be confusing with many placeholders.
str.format() – more flexible, but still requires you to repeat variable names or positions.
f‑strings – concise, evaluated at runtime, and can include any expression.

Embedding expressions

You can place any valid Python expression inside {}:

import math
radius = 3
area_msg = f"The area of a circle with radius {radius} is {math.pi * radius ** 2:.2f}"


- math.pi * radius ** 2 computes the area.
- :.2f is a format specifier that tells Python to format the result as a floating‑point number with two decimal places.

Why the format spec works
After the expression, a colon : separates the value from its format spec. The spec follows the same rules as str.format(). Python calls the object's __format__ method, passing the spec string. For numbers, :.2f means fixed‑point notation with two digits after the decimal point.

Formatting numbers, dates, and more

from datetime import datetime

value = 1234.5678
today = datetime(2023, 9, 1, 14, 30)

info = f"""Value: {value:,.2f}
Date : {today:%Y-%m-%d %H:%M}
Hex : {int(value):#06x}
"""
print(info)


Explanation of each field:

- {value:,.2f} – adds commas as thousands separators and keeps two decimals.
- {today:%Y-%m-%d %H:%M} – uses datetime’s strftime‑style spec to format the date.
- {int(value):#06x} – converts value to an integer, then formats it as hexadecimal with a 0x prefix, padded to 6 characters.

Escaping braces
If you need a literal { or } in the output, double them:

msg = f"Set notation: {{1, 2, 3}}"
# Output: Set notation: {1, 2, 3}


Performance note
Because f‑strings are evaluated at runtime and compiled into a series of string concatenations, they are generally faster than str.format() and %‑formatting, especially when many placeholders are used.

Complete runnable example

(continued below 👇)
#!/usr/bin/env python3
"""
Demonstrates various f‑string capabilities:
- Simple variable insertion
- Expression evaluation
- Number formatting
- Date formatting
- Hexadecimal representation
- Escaping braces
"""

from datetime import datetime

def main():
# Simple variables
user = "Grace"
tasks = 5

# Expression inside f‑string
greeting = f"Hi {user}, you have {tasks * 2} pending items."

# Number with commas and two decimals
price = 1999.99
price_msg = f"Total price: ${price:,.2f}"

# Current date and time formatting
now = datetime.now()
date_msg = f"Report generated on {now:%A, %d %B %Y at %H:%M:%S}"

# Hexadecimal with prefix and zero‑padding
checksum = 0x1a3f
hex_msg = f"Checksum: {checksum:#06x}"

# Escaping braces
set_msg = f"Example set: {{'apple', 'banana', 'cherry'}}"

# Combine everything
report = "\n".join([greeting, price_msg, date_msg, hex_msg, set_msg])
print(report)

if __name__ == "__main__":
main()


Walk‑through

1. Imports – datetime is needed for date formatting.
2. Variables – user, tasks, price, checksum hold basic data.
3. greeting – {tasks * 2} multiplies tasks by 2 inside the string, demonstrating expression evaluation.
4. price_msg – {price:,.2f} inserts price with a comma as thousand separator and exactly two decimal places.
5. date_msg – {now:%A, %d %B %Y at %H:%M:%S} uses a strftime‑style spec to produce a human‑readable timestamp.
6. hex_msg – {checksum:#06x} formats checksum as a zero‑padded hexadecimal (0x1a3f).
7. set_msg – {{...}} escapes braces so the output shows literal curly braces.
8. report – "\n".join([...]) concatenates all lines with newline characters.
9. print(report) – outputs the fully formatted multi‑line string to the console.

Running this script prints something like:

Hi Grace, you have 10 pending items.
Total price: $1,999.99
Report generated on Tuesday, 12 October 2026 at 14:23:45
Checksum: 0x1a3f
Example set: {'apple', 'banana', 'cherry'}


Each line demonstrates a different facet of f‑string power, giving you a solid foundation to apply them in real projects.

Key take‑aways

- Prefix a string with f (or F) to enable inline expression evaluation.
- Use {} to insert variables, call functions, or run arithmetic directly.
- After a colon :, provide a format spec to control number, date, or custom formatting.
- Escape literal braces by doubling them ({{ or }}).
- f‑strings are concise, readable, and usually the fastest built‑in formatting option.
Which part of an f‑string specifies how a value should be displayed, such as number of decimal places?
Anonymous Quiz
0%
The expression before the colon
50%
The format spec after the colon
0%
The variable name inside braces
50%
The leading 'f' character
📘 Day 6: Numbers and arithmetic operators

Python treats every numeric value as an object that knows its own type and how to behave with operators. Understanding the why behind numbers and arithmetic operators helps you predict results, avoid bugs, and write clearer code.

Basic numeric types
- int – whole numbers, unlimited precision (e.g., -3, 0, 42).
- float – real numbers stored in double‑precision binary format (e.g., 3.14, -0.001).
- complex – numbers with a real and an imaginary part (2 + 3j).

Each type implements the standard arithmetic operators (+, -, *, /, //, %, **). When you combine two numbers, Python follows a set of rules:

1. Type promotion – if the operands differ, the smaller type is upgraded to the larger one so the operation can be performed without loss of information.
Example: int + float → both become float.
2. Operator semantics – each operator has a precise definition that the type’s implementation follows.
3. Precedence and associativity – Python evaluates operators in a fixed order (e.g., ** before *, /, //, %, which are before + and -). Parentheses () can override this order.

The arithmetic operators in detail

- + (addition) – adds two numbers. For int and float it’s straightforward; for complex it adds both real and imaginary parts.
- - (subtraction) – subtracts right operand from left.
- * (multiplication) – multiplies. With complex, it follows the algebraic rule (a+bj)*(c+dj).
- / (true division) – always returns a float, even if both operands are int. Python uses real‑number division, not integer truncation.
- // (floor division) – divides then floors the result to the nearest lower integer (or lower whole number for negatives). The result type matches the left operand’s type when possible.
- % (modulo) – returns the remainder after floor division. It satisfies the identity a == (a // b) * b + (a % b).
- ** (exponentiation) – raises left operand to the power of right operand. Supports fractional exponents, which produce a float.

Why does // floor the result?

Python defines floor division as:

a // b  ==  math.floor(a / b)


math.floor always moves toward negative infinity. This behaviour is consistent with the modulo operator’s identity above, ensuring that (a // b) * b + (a % b) exactly reconstructs the original a.

A complete, runnable example

Below is a short script that touches every numeric type and each arithmetic operator. Run it line‑by‑line to see the output and understand what’s happening.

# Numbers and arithmetic operators demo

# 1️⃣ Define values of different numeric types
a = 7 # int: whole number
b = 3.5 # float: decimal number
c = 2 + 3j # complex: real + imag*j

# 2️⃣ Basic operations
add = a + b # int + float → float
sub = a - b # subtraction → float
mul = a * b # multiplication → float
true_div = a / b # true division → float
floor_div = a // b # floor division → int (floors 2.0)
mod = a % b # remainder after floor division → float
exp = a ** 2 # exponentiation → int
complex_mul = c * (1 - 1j) # complex multiplication

# 3️⃣ Show results
print("a (int) =", a)
print("b (float) =", b)
print("c (complex) =", c)
print("a + b =", add) # 10.5
print("a - b =", sub) # 3.5
print("a * b =", mul) # 24.5
print("a / b =", true_div) # 2.0
print("a // b =", floor_div) # 2
print("a % b =", mod) # 0.5
print("a ** 2 =", exp) # 49
print("c * (1-1j) =", complex_mul) # (5+1j)


Line‑by‑line walk‑through

(continued below 👇)
- a = 7 creates an int object holding the value 7.
- b = 3.5 creates a float object.
- c = 2 + 3j creates a complex object where 2 is the real part and 3j is the imaginary part.
- add = a + b triggers type promotion: a is promoted to float, then addition yields 10.5.
- true_div = a / b always returns a float; even though 7 / 3.5 is mathematically 2, the result is 2.0.
- floor_div = a // b computes 7 / 3.5 = 2.0 then floors it to 2. Because the left operand is an int, the result stays an int.
- mod = a % b satisfies 7 == (7 // 3.5) * 3.5 + (7 % 3.5), so 7 % 3.5 equals 0.5.
- exp = a ** 2 squares 7, returning an int (49).
- complex_mul = c * (1 - 1j) uses the algebraic rule (a+bj)*(c+dj) = (ac‑bd) + (ad+bc)j. The result is (5+1j).

Running the script prints each intermediate value, confirming how Python’s numeric tower and operator definitions work together.

Key take‑aways

- Type promotion guarantees operations don’t lose precision.
- / vs //: true division always yields a float; floor division discards the fractional part toward negative infinity.
- Operator precedence follows the standard mathematical hierarchy; use parentheses to make intent explicit.
- Complex numbers behave algebraically, and the same operators apply.

Understanding these fundamentals makes higher‑level numeric work—statistics, scientific computing, graphics—much more predictable.
In Python, what is the result of the expression `7 // 3`?
Anonymous Quiz
33%
2
0%
2.3333333333333335
0%
3
67%
1
📘 Day 7: input() and type conversion

Understanding input() and Type Conversion in Python

When you write a program that interacts with a user, the most common way to get data is the built‑in input() function. It looks simple:

name = input("Enter your name: ")


But what input() actually returns, and why we often need to convert that value, is a fundamental concept that underpins every interactive script.

1️⃣ What input() really does

1. Displays a prompt – the string you pass ("Enter your name: ").
2. Waits for the user to type – everything the user types until they press Enter is captured.
3. Returns a str object – even if the user typed digits, the result is still a string.

Why a string?
The underlying operating system sends the typed characters as a sequence of bytes. Python decodes those bytes using the default text encoding (usually UTF‑8) and builds a string object. This design keeps input() simple and language‑agnostic: the function never guesses the intended data type.

2️⃣ Why you need type conversion

Most programs need numbers, dates, booleans, or other non‑text data. If you try to use the raw string as a number, Python will raise a TypeError or give you unexpected results:

age = input("Enter your age: ")
print(age + 10) # ❌ TypeError: can only concatenate str (not "int") to str


Here age is a string like "27". Adding 10 to a string would mean concatenation, not arithmetic. To perform math we must turn the string into an integer (or a float if decimals are allowed).

3️⃣ The basic conversion functions

Function — Purpose — Typical error

int(s) — Convert string s to an integer — ValueError if s isn’t a valid integer ("12a" )
float(s) — Convert string s to a floating‑point number — ValueError if s isn’t a valid float ("abc" )
bool(s) — Convert string s to a boolean (False only if s is empty or "0" ) — Rarely raises, but truthiness may be confusing

Why these work: Each function parses the characters of the string according to the rules of the target numeric format. If the pattern doesn’t match, Python raises a ValueError to signal that conversion is impossible.

4️⃣ Safe conversion with error handling

A robust script never assumes the user will type the correct format. Use try / except to catch conversion failures and react gracefully:

while True:
raw = input("Enter a positive integer: ")
try:
number = int(raw)
if number > 0:
break # valid input, exit loop
else:
print("⚠️ Must be greater than zero.")
except ValueError:
print("⚠️ That's not an integer. Try again.")


What happens step‑by‑step

1. input() returns whatever the user typed (raw).
2. int(raw) attempts to parse it.
3. If parsing succeeds, we get an int stored in number.
4. If parsing fails, Python jumps to the except block, where we inform the user and repeat.

5️⃣ Full example – a simple calculator

Below is a complete, runnable script that demonstrates prompting, type conversion, error handling, and using the converted values:

(continued below 👇)
# Simple calculator: adds two numbers entered by the user
def get_number(prompt: str) -> float:
"""Repeatedly ask for a number until the user provides a valid float."""
while True:
raw = input(prompt)
try:
# Convert the raw string to a floating‑point number
return float(raw)
except ValueError:
# Inform the user why the conversion failed
print("❌ Invalid number, please type digits like 3.14 or 42.")

def main():
print("🧮 Welcome to the Mini Calculator!")
# Get the first operand
a = get_number("Enter the first number: ")
# Get the second operand
b = get_number("Enter the second number: ")

# Perform addition – now we can use '+' as arithmetic because a & b are floats
result = a + b

# Show the result, formatted to two decimal places
print(f"✅ The sum of {a:.2f} and {b:.2f} is {result:.2f}")

if __name__ == "__main__":
main()


Walk‑through

- def get_number(prompt: str) -> float: – a helper that encapsulates the input‑convert‑retry pattern.
- raw = input(prompt) – captures the user’s raw text.
- float(raw) – attempts to turn that text into a numeric value (float).
- except ValueError: – catches the situation where the text isn’t a valid number and prompts again.
- a = get_number(...) & b = get_number(...) – we now have two float objects, ready for arithmetic.
- result = a + b – normal numeric addition works because both operands are numbers, not strings.
- print(f"...") – formatted output shows the numbers with two decimal places, demonstrating that they are indeed numeric.

6️⃣ Common pitfalls & best practices

- Never trust raw input – always validate and convert.
- Prefer float for generic numeric entry – it accepts both integer‑style ("5") and decimal ("5.0").
- Use strip() if you want to ignore surrounding whitespace: raw = input(...).strip().
- Remember that bool("False") is True – the string is non‑empty, so it evaluates to True. Use explicit checks (raw.lower() in ("true", "yes", "1")).
- Separate concerns – keep prompting/validation in its own function (as shown) to keep the main logic clean.

7️⃣ Quick bolded checklist

- input() always returns a str.
- Convert with int(), float(), or custom parsing.
- Wrap conversions in try/except to handle bad data.
- Validate ranges (e.g., positive numbers) after conversion.
- Never mix raw strings with numeric operators.

Mastering input() and type conversion is the first step toward building reliable, user‑friendly command‑line applications. Once you internalize the why behind each step, you’ll write safer code with confidence.
What does the built‑in `input()` function return in Python?
Anonymous Quiz
0%
An integer
100%
A string
0%
A list
0%
A boolean