THINK IN PYTHON
From Zero to Job-Ready Developer
CHAPTER 2
Variables, Data Types & Operators in Depth
int · float · str · bool · list · tuple · dict · set · type() · casting · operators · operator precedence
1. Why This Topic Exists
Every program ever written does one thing at its core: it stores data, transforms data, and
outputs data.
Variables are how you store it. Data types are what kind of thing it is. Operators are how you
transform it.
Get these three wrong and no amount of clever logic will save you. Get them right and every
chapter that follows — functions, OOP, APIs, databases — becomes natural.
2. Real-World Problem — The Paytm Crash
A junior developer at a FinTech startup writes this code for a UPI transfer:
The bug that caused a production crash
sender = input('Sender name: ')
amount = input('Amount (Rs): ')
balance = 5000
# Attempt to check if balance is sufficient
if balance > amount:
print(f'Transfer of Rs.{amount} approved')
else:
print('Insufficient balance')
What went wrong?
input() always returns a string.
amount is '2000' (a string), not 2000 (an integer).
Python compares: 5000 > '2000'
In Python 3 this raises: TypeError: '>' not supported between 'int' and 'str'
Production is down. Users can't transfer money. All because of one missing int().
This exact category of bug — wrong data type — is the most common source of runtime
crashes in beginner Python code. This chapter eliminates it entirely.
3. Mental Model — JARVIS's Storage System
Tony Stark's JARVIS doesn't just remember things — it remembers what kind of thing each
piece of data is, so it can use it correctly.
When Stark says 'JARVIS, what's the reactor level?' — JARVIS doesn't return the word
'hundred'. It returns the number 100 so Stark can do math on it.
When Stark says 'JARVIS, display my name on the HUD' — JARVIS doesn't return 73 (ASCII
code). It returns the text 'Tony Stark' so it can be displayed.
Python works the same way. Every value has a type. The type determines what operations are
legal on it.
JARVIS analogy Python reality
Reactor level: 100 (a number) int — can add, subtract, compare
Name: 'Tony Stark' (text) str — can slice, concatenate, format
Suit active: Yes/No bool — True or False only
Missile count: 12 (whole number) int — no decimals
Battery: 97.3% (decimal) float — has decimal precision
Weapon list: [repulsor, missile] list — ordered, changeable collection
4. Core Concept — Variables in Depth
4.1 What a Variable Actually Is
A variable is not a box that contains a value. It is a label that points to an object in memory.
This distinction matters more than it seems:
Variables are labels — proof
x = 1000
y = x # y points to the SAME object as x
print(id(x)) # e.g. 140234567890
print(id(y)) # SAME address — same object
x = 2000 # x now points to a NEW object
print(id(x)) # different address
print(id(y)) # y still points to 1000 — unchanged
print(y) # 1000
Why this matters in production
When you do: list_b = list_a
You do NOT get a copy. You get TWO labels pointing to ONE list.
Changing list_b also changes list_a.
This causes bugs that are nearly impossible to find without this mental model.
We cover this fully in the Lists chapter. For now: labels, not boxes.
4.2 Variable Naming Rules and Conventions
Rule Valid example Invalid example
Start with letter or underscore user_name = 'Rahul' 2name = 'Rahul'
Letters, digits, underscores order_123 = True order-123 = True
only
Case sensitive Amount and amount are different (not a syntax error, just
confusing)
Cannot be a reserved keyword total = 100 class = 100 (class is reserved)
Convention Rule Example
snake_case Variables and functions user_balance, get_order_total()
UPPER_SNAKE_C Constants that never change GST_RATE = 0.18, MAX_RETRIES
ASE =3
PascalCase Class names (Chapter 7) NetflixUser, PaytmTransaction
_leading_underscor Private/internal use _cached_token, _validate()
e
4.3 Multiple Assignment and Swapping
Assignment patterns every developer uses
# Assign same value to multiple variables
a = b = c = 0
print(a, b, c) # 0 0 0
# Assign multiple values in one line (tuple unpacking)
name, age, city = 'Priya', 28, 'Mumbai'
print(name) # Priya
print(age) # 28
# Swap — Python's cleanest trick
x, y = 10, 20
x, y = y, x
print(x, y) # 20 10
# No temp variable needed — Python evaluates the right side fully first
# Unpack with * (star) — collect remainders
first, *middle, last = [1, 2, 3, 4, 5]
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
5. Data Types — All Eight, In Depth
Python has 8 built-in data types. This chapter covers all of them — what they are, how they
behave, and exactly where each one trips up beginners.
Type Category Mutable?
int Numeric No — immutable
float Numeric No — immutable
str Text No — immutable
bool Boolean No — immutable
list Sequence Yes — mutable
tuple Sequence No — immutable
dict Mapping Yes — mutable
set Collection Yes — mutable
5.1 int — Whole Numbers
Integers in Python have no size limit. You can work with numbers as large as your RAM allows
— no overflow errors unlike Java or C.
int — everything you need to know
# Basic integers
followers = 4_200_000 # Underscores for readability (Python 3.6+)
temperature = -12
score = 0
# Python handles enormous numbers natively
googol = 10 ** 100 # 10 to the power 100 — prints all 101 digits
# Integer bases
binary = 0b1010 # Binary → 10
octal = 0o12 # Octal → 10
hex_val = 0x0A # Hex → 10
print(binary, octal, hex_val) # 10 10 10
# Integer methods
print(abs(-42)) # 42 — absolute value
print(pow(2, 10)) # 1024 — same as 2**10
print(divmod(17, 5)) # (3, 2) — quotient AND remainder together
Corporate usage — int in Swiggy's backend
order_id: int = 982345001
items_count: int = 3
delivery_time_minutes: int = 32
All quantities, IDs, counts, and durations are integers.
Never use float for these — rounding errors in loops will bite you.
5.2 float — Decimal Numbers
float — and the trap every beginner hits
price = 1299.99
gst = 0.18
rating = 4.7
# Scientific notation
avogadro = 6.022e23 # 6.022 * 10^23
nano = 1e-9 # 0.000000001
# THE FAMOUS FLOAT TRAP
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
# This is NOT a Python bug.
# Computers store decimals in binary (base-2).
# 0.1 in binary is 0.0001100110011... (infinite repeating)
# The storage rounds it — tiny error accumulates.
# Fix 1: round() for display
print(round(0.1 + 0.2, 2)) # 0.3
# Fix 2: [Link]() for comparisons
import math
print([Link](0.1 + 0.2, 0.3)) # True
# Fix 3: decimal module for financial calculations
from decimal import Decimal
total = Decimal('0.1') + Decimal('0.2')
print(total) # 0.3 -- exact
Rule for financial code
Never use float for money in production.
Use the decimal module — Paytm, Zerodha, Stripe all do this.
Float errors compound over millions of transactions into real rupees lost.
5.3 str — Text and String Operations
Strings are immutable sequences of characters. Every string operation creates a new string — it
never modifies the original.
str — creation and indexing
# Three ways to create strings
single = 'Hello, World!'
double = "Hello, World!"
multi = '''
This is a
multi-line string
'''
# Indexing — positive and negative
name = 'Netflix'
print(name[0]) # 'N' — first character
print(name[-1]) # 'x' — last character
print(name[2:5]) # 'tfl' — slice [start:stop] stop is exclusive
print(name[:3]) # 'Net' — from start
print(name[3:]) # 'flix' — to end
print(name[::-1]) # 'xilfteN' — reversed
str — the methods used in every real project
app = ' spotify '
print([Link]()) # 'spotify' — remove whitespace
print([Link]().upper()) # 'SPOTIFY'
print([Link]().title()) # 'Spotify'
sentence = 'order confirmed from swiggy'
print([Link]()) # 'Order confirmed from swiggy'
print([Link]('swiggy', 'Zomato'))
# 'order confirmed from Zomato'
csv_line = 'Rahul,28,Mumbai,Engineer'
fields = csv_line.split(',') # ['Rahul', '28', 'Mumbai', 'Engineer']
print(fields[0]) # 'Rahul'
# join — the opposite of split
words = ['Python', 'is', 'powerful']
print(' '.join(words)) # 'Python is powerful'
print('-'.join(words)) # 'Python-is-powerful'
url = '[Link]
print([Link]('https')) # True
print([Link]('/users')) # True
print('github' in url) # True — membership check
# find vs index
print([Link]('github')) # 8 — returns -1 if not found
print([Link]('github')) # 8 — raises ValueError if not found
f-strings — the professional standard
name = 'Virat'
runs = 100
average = 58.455
# Basic f-string
print(f'{name} scored {runs} runs')
# Format specifiers
print(f'Average: {average:.2f}') # 58.46 — 2 decimal places
print(f'Runs: {runs:05d}') # 00100 — zero-padded, 5 wide
print(f'Big number: {1234567:,}') # 1,234,567 — comma separator
print(f'Percentage: {0.876:.1%}') # 87.6%
print(f'Hex: {255:#x}') # 0xff
# Expressions inside f-strings
items = 3
price = 299
print(f'Total: Rs.{items * price:,}') # Total: Rs.897
5.4 bool — True, False, and the Truthiness Trap
bool is a subclass of int in Python. True equals 1 and False equals 0. This is not just trivia — it
enables some powerful patterns.
bool — and why it surprises everyone
# The basics
is_premium = True
is_blocked = False
# bool is a subclass of int
print(True + True) # 2
print(True * 5) # 5
print(False + 1) # 1
# Counting Trues in a list — used in data analysis constantly
results = [True, False, True, True, False, True]
print(sum(results)) # 4 — count of True values
# Comparisons always return bool
balance = 5000
print(balance > 0) # True
print(type(balance > 0)) # <class 'bool'>
Truthy and Falsy — the complete list
# FALSY — these all evaluate to False in a boolean context
# 0 0.0 0j '' [] () {} set() None False
# TRUTHY — everything else
# Any non-zero number, non-empty string, non-empty collection
# The trap: bool('False') is True
print(bool('False')) # True — non-empty string
print(bool('0')) # True — non-empty string
print(bool(0)) # False — the number zero
print(bool([])) # False — empty list
print(bool([0])) # True — list with one element (even if 0)
# Pythonic usage
username = input('Username: ')
if username: # Truthy check — empty string is falsy
print(f'Welcome, {username}')
else:
print('Username cannot be empty')
5.5 list — Ordered, Mutable Collections
A list is Python's most used data structure. It holds an ordered collection of any type — and
unlike strings or tuples, you can change it after creation.
list — creation and core operations
# Creation
playlist = ['Kesariya', 'Raataan Lambiyan', 'Tum Hi Ho']
prices = [199, 299, 499, 999]
mixed = ['Rahul', 28, True, 3.14] # any types
empty = []
# Indexing and slicing — same as str
print(playlist[0]) # 'Kesariya'
print(playlist[-1]) # 'Tum Hi Ho'
print(prices[1:3]) # [299, 499]
# Mutation — lists can be changed
playlist[0] = 'Jai Ho'
print(playlist) # ['Jai Ho', 'Raataan Lambiyan', 'Tum Hi Ho']
# Common methods
[Link]('Chaiyya Chaiyya') # add to end
[Link](1, 'Dil Chahta Hai') # insert at index 1
[Link]('Tum Hi Ho') # remove by value
popped = [Link]() # remove and return last
[Link]() # sort in place
rev = playlist[::-1] # reversed copy
print(len(playlist)) # length
print('Jai Ho' in playlist) # membership check
The copy trap — most common list bug
cart_a = ['iPhone', 'AirPods']
cart_b = cart_a # NOT a copy — same object, two labels
cart_b.append('MacBook')
print(cart_a) # ['iPhone', 'AirPods', 'MacBook'] -- cart_a also changed!
Fix: cart_b = cart_a.copy() OR cart_b = cart_a[:]
For nested lists, use: import copy; cart_b = [Link](cart_a)
5.6 tuple — Ordered, Immutable Collections
A tuple is like a list that cannot be changed. Use it for data that should never be modified —
coordinates, RGB colors, database records.
tuple — when to use it
# Creation
coordinates = (28.6139, 77.2090) # Delhi lat, long
rgb_red = (255, 0, 0)
db_record = ('user_001', 'Priya', 'priya@[Link]')
single = (42,) # MUST have trailing comma for single-
item tuple
# Access — same as list
print(coordinates[0]) # 28.6139
print(db_record[-1]) # 'priya@[Link]'
# Immutability
# coordinates[0] = 0 # TypeError: 'tuple' object does not support item
assignment
# Tuple unpacking — used everywhere
lat, lon = coordinates
print(f'Latitude: {lat}, Longitude: {lon}')
# Functions returning multiple values actually return tuples
def get_min_max(numbers):
return min(numbers), max(numbers) # returns a tuple
low, high = get_min_max([3, 1, 9, 5, 7])
print(low, high) # 1 9
# Why tuple over list?
# 1. Communicates intent: this data should not change
# 2. Tuples are faster and use less memory
# 3. Tuples can be dict keys (lists cannot)
5.7 dict — Key-Value Storage
A dictionary is the most powerful built-in data structure in Python. It maps unique keys to values
and retrieves them in O(1) constant time — no matter how large it gets.
dict — the data structure behind every real app
# Creation
user = {
'id': 'usr_001',
'name': 'Kiran Rao',
'email': 'kiran@[Link]',
'is_premium': True,
'balance': 2500.00,
}
# Access
print(user['name']) # 'Kiran Rao'
print([Link]('phone')) # None — safe, no KeyError
print([Link]('phone', 'N/A')) # 'N/A' — default value
# Modify
user['balance'] = 3000.00 # update existing
user['city'] = 'Hyderabad' # add new key
del user['email'] # remove key
# Iteration
for key in user: # iterates keys
print(key)
for key, value in [Link](): # iterates key-value pairs
print(f'{key}: {value}')
# Membership check
print('name' in user) # True — checks keys only
# Common patterns
keys = list([Link]())
values = list([Link]())
print(len(user)) # number of key-value pairs
dict — advanced patterns used in production
# setdefault — add key only if it does not exist
[Link]('referral_count', 0) # adds 0 if key missing
# update — merge another dict
extra = {'city': 'Chennai', 'plan': 'Gold'}
[Link](extra)
# Dict comprehension — build dicts from data
prices = {'biryani': 299, 'pizza': 499, 'burger': 199}
gst_prices = {item: price * 1.18 for item, price in [Link]()}
print(gst_prices)
# {'biryani': 353.42, 'pizza': 589.42, 'burger': 235.42}
# Nested dicts — JSON API responses look like this
order = {
'order_id': 'ORD_7823',
'restaurant': {'name': 'Behrouz', 'city': 'Bangalore'},
'items': [{'name': 'Biryani', 'qty': 2}],
'status': 'out_for_delivery',
}
print(order['restaurant']['name']) # 'Behrouz'
print(order['items'][0]['qty']) # 2
5.8 set — Unique, Unordered Collections
A set stores unique values with no duplicates and no guaranteed order. Its superpower is
membership testing — checking if a value exists in a set is instant regardless of size.
set — deduplication and membership
# Creation
genres = {'Action', 'Drama', 'Comedy', 'Drama', 'Action'}
print(genres) # {'Action', 'Drama', 'Comedy'} — duplicates gone
# Convert list to set to remove duplicates
tags = ['python', 'fastapi', 'python', 'docker', 'fastapi']
unique_tags = set(tags)
print(unique_tags) # {'python', 'fastapi', 'docker'}
# Membership — O(1) lookup regardless of size
banned_users = {'spammer_01', 'bot_99', 'fraud_42'}
incoming_user = 'bot_99'
if incoming_user in banned_users:
print('Access denied')
# Set operations
users_a = {'Priya', 'Kiran', 'Ravi', 'Anita'}
users_b = {'Kiran', 'Anita', 'Suresh', 'Meena'}
print(users_a & users_b) # Intersection: {'Kiran', 'Anita'}
print(users_a | users_b) # Union: all unique users
print(users_a - users_b) # Difference: in A but not B
print(users_a ^ users_b) # Symmetric diff: in one but not both
6. Type Conversion — Casting Data
Type conversion means changing a value from one type to another. Python does almost nothing
implicitly — you must be explicit. This is a feature, not a limitation.
Explicit type conversion — the complete reference
# str → int
age_text = '25'
age = int(age_text) # 25
# str → float
price_text = '1299.99'
price = float(price_text) # 1299.99
# int/float → str
total = 3750
msg = 'Total: Rs.' + str(total) # 'Total: Rs.3750'
# int → float and back
print(float(10)) # 10.0
print(int(9.9)) # 9 — truncates, does NOT round
print(round(9.9)) # 10 — rounds
# Anything → bool
print(bool(0)) # False
print(bool('')) # False
print(bool([])) # False
print(bool(1)) # True
print(bool('hi')) # True
# str → list of characters
chars = list('Netflix') # ['N','e','t','f','l','i','x']
# list → set (deduplicate)
unique = set([1, 2, 2, 3, 3, 3]) # {1, 2, 3}
Handling conversion errors safely
# This crashes:
# age = int('twenty five') # ValueError
# Safe conversion with try/except
def safe_int(value, default=0):
try:
return int(value)
except (ValueError, TypeError):
return default
print(safe_int('25')) # 25
print(safe_int('abc')) # 0 — default
print(safe_int(None)) # 0 — default
print(safe_int('10', -1)) # 10
# Use this pattern anywhere you accept user input or API data
7. Operators — All Six Categories
7.1 Arithmetic Operators
a, b = 17, 5
print(a + b) # 22 — Addition
print(a - b) # 12 — Subtraction
print(a * b) # 85 — Multiplication
print(a / b) # 3.4 — True division (always float)
print(a // b) # 3 — Floor division (integer result)
print(a % b) # 2 — Modulus (remainder)
print(a ** b) # 1419857 — Exponentiation (17 to the 5th)
# Real-world usage
order_value = 850
gst_rate = 0.18
gst_amount = order_value * gst_rate # 153.0
total = order_value + gst_amount # 1003.0
# Check even/odd with modulus
user_id = 10247
if user_id % 2 == 0:
print('Even user ID — Cohort A')
else:
print('Odd user ID — Cohort B')
7.2 Comparison Operators
# All return True or False
x, y = 10, 20
print(x == y) # False — Equal to
print(x != y) # True — Not equal to
print(x > y) # False — Greater than
print(x < y) # True — Less than
print(x >= 10) # True — Greater than or equal
print(x <= 5) # False — Less than or equal
# Chained comparisons — Python's clean syntax
age = 25
print(18 <= age <= 60) # True — very Pythonic
# Real world: Ola surge pricing
hour = 8
demand = 0.9
is_surge = (7 <= hour <= 10) and demand > 0.8
print(is_surge) # True
7.3 Logical Operators
# and — both must be True
# or — at least one must be True
# not — reverses True/False
age = 23
has_id = True
is_banned = False
can_enter = age >= 18 and has_id and not is_banned
print(can_enter) # True
# Short-circuit evaluation — Python stops early
# and: if first is False, second is never evaluated
# or: if first is True, second is never evaluated
# Practical example: safe dict lookup
user = {'name': 'Priya'}
# If 'email' key missing, .get() returns None, which is falsy
# 'not verified' is returned without crashing
email_status = [Link]('email') or 'not verified'
print(email_status) # 'not verified'
7.4 Assignment Operators
score = 100
score += 10 # score = score + 10 → 110
score -= 5 # score = score - 5 → 105
score *= 2 # score = score * 2 → 210
score //= 3 # score = score // 3 → 70
score **= 2 # score = score ** 2 → 4900
score %= 1000 # score = score % 1000 → 900
print(score) # 900
# Walrus operator := (Python 3.8+) — assign and test in one line
import re
data = 'Order: ORD_9823'
if m := [Link](r'ORD_\d+', data):
print(f'Found order ID: {[Link]()}') # Found order ID: ORD_9823
7.5 Membership Operators — in and not in
# in — returns True if value exists in sequence
# not in — returns True if value does NOT exist
playlist = ['Tum Hi Ho', 'Kesariya', 'Raataan Lambiyan']
print('Kesariya' in playlist) # True
print('Shape of You' not in playlist) # True
# Works on str, list, tuple, dict (keys), set
email = 'user@[Link]'
print('@' in email) # True
print('gmail' in email) # True
user = {'name': 'Kiran', 'plan': 'Premium'}
print('plan' in user) # True — checks keys
print('Premium' in user) # False — values not checked by default
7.6 Identity Operators — is and is not
# == checks VALUE equality
# is checks IDENTITY (same object in memory)
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True — same values
print(a is b) # False — different objects in memory
print(a is c) # True — same object
# Only use 'is' to compare with None, True, False
result = None
if result is None: # Correct
print('No result yet')
# NEVER do this:
# if result == None: — works but misleading, not Pythonic
# Small int caching (Python optimisation)
x = 256
y = 256
print(x is y) # True — Python caches -5 to 256
x = 257
y = 257
print(x is y) # False — beyond cache range
8. Operator Precedence
Python evaluates operators in a specific order. Get this wrong and your calculations silently
produce the wrong answer.
Precedence (High to Low) Operators
1. Parentheses ()
2. Exponentiation **
3. Unary +x, -x, ~x
4. Multiplication / Division *, /, //, %
5. Addition / Subtraction +,-
6. Bitwise shift << , >>
7. Bitwise AND &
8. Bitwise OR / XOR |,^
9. Comparison ==, !=, >, <, >=, <=, is, in
10. Boolean NOT not
11. Boolean AND and
12. Boolean OR or
13. Assignment =, +=, -=, ...
Precedence — where beginners get surprised
# What is the answer?
result = 2 + 3 * 4
print(result) # 14 — NOT 20. * before +
# Always use parentheses to be explicit
result = (2 + 3) * 4
print(result) # 20
# Real-world example: GST calculation
base = 1000
gst_rate = 18
# Wrong — accidentally divides only 18 by 100
wrong = base * gst_rate / 100 + base
print(wrong) # 1180.0 (coincidentally right here, but logic is fragile)
# Clear — intent is obvious
gst = base * (gst_rate / 100) # 180.0
total = base + gst # 1180.0
print(total)
9. Common Mistakes
Mistake 1 — Not converting input()
Wrong: amount = input('Amount: ') then total = amount * 1.18
Error: TypeError — cannot multiply str by float
Fix: amount = float(input('Amount: '))
Mistake 2 — Using float for money
Wrong: balance = 999.99 + 0.01 → balance is 1000.0000000000001
Fix: from decimal import Decimal; use Decimal('999.99') + Decimal('0.01')
Mistake 3 — == vs is
Wrong: if result == None (works but non-Pythonic and can have edge cases)
Fix: if result is None
Mistake 4 — Mutating a shared list
Wrong: list_b = list_a (both point to same object)
Fix: list_b = list_a.copy() or list_b = list_a[:]
Mistake 5 — Single-element tuple missing comma
Wrong: t = (42) → this is just the integer 42 in parentheses
Fix: t = (42,) → trailing comma makes it a tuple
Mistake 6 — Using a list as a dict key
Wrong: d = {[1, 2]: 'value'} → TypeError: unhashable type: 'list'
Fix: d = {(1, 2): 'value'} → tuples are hashable, lists are not
10. Debugging Section
Debug drill — spot and fix all 5 bugs
# Buggy Zomato order system — find all the bugs
item_name = input('Item: ')
quantity = input('Quantity: ')
price = input('Unit price: ')
subtotal = quantity * price
gst = subtotal * 18 / 100
total = subtotal + gst
order = {
[item_name]: quantity,
}
single_item = (item_name)
if total == None:
print('No total calculated')
Fixed version — all bugs corrected with explanation
item_name = input('Item: ')
quantity = int(input('Quantity: ')) # Bug 1: was str, needs int
price = float(input('Unit price: ')) # Bug 2: was str, needs float
subtotal = quantity * price
gst = subtotal * 0.18 # Bug 3: use 0.18 not 18/100 for
clarity
total = subtotal + gst
order = {
item_name: quantity, # Bug 4: list [item_name] as key
crashes
}
single_item = (item_name,) # Bug 5: missing trailing comma
if total is None: # Bug 6: use 'is None', not '==
None'
print('No total calculated')
print(f'Total: Rs.{total:.2f}')
11. Interview Layer
Top 10 Screening Questions
1. What is the difference between a list and a tuple?
2. What is the difference between a list and a set?
3. What is the difference between a dict and a set?
4. What does input() always return? Why does this matter?
5. What is the difference between == and is in Python?
6. Name all falsy values in Python.
7. What is the difference between / and // operators?
8. What is the float precision problem? How do you fix it in financial code?
9. What is type casting? Give three real examples.
10. What is operator precedence? Give an example where it matters.
Top 5 Coding Questions
11. Write a function that takes a list of Swiggy orders (as dicts) and returns the total bill with
18% GST.
12. Given a string of comma-separated usernames, return a set of unique usernames.
13. Write a safe_divide(a, b) function that returns None if b is zero.
14. Given a dict of product prices, create a new dict with only items under Rs. 500.
15. Write code that takes a user's name and birth year as input and prints their age and a
personalised Netflix-style welcome message.
Top 3 Tricky Questions
16. What is the output of: print(0.1 + 0.2 == 0.3) — and WHY?
17. Is bool a subclass of int in Python? Prove it with code.
18. Why can a tuple be a dict key but a list cannot?
Expected Answers — Written Out
Q: List vs Tuple vs Set — when to use each?
list: ordered, mutable, allows duplicates → use for sequences that change (cart, playlist)
tuple: ordered, immutable, allows duplicates → use for fixed data (coordinates, DB records)
set: unordered, mutable, NO duplicates → use for unique collections and fast membership
checks
Q: Why can't a list be a dict key?
Dict keys must be hashable — their hash value cannot change after creation.
Lists are mutable — you can change them after creation, which would change their hash.
Tuples are immutable — their hash never changes, so they are valid dict keys.
Strings, ints, floats, booleans, and tuples (of hashable types) are all valid keys.
Q: 0.1 + 0.2 == 0.3 — explain the output
Output: False
Reason: computers store floats in binary (base-2). 0.1 in binary is a repeating fraction,
so it cannot be represented exactly. Tiny rounding errors accumulate.
0.1 + 0.2 is actually 0.30000000000000004 internally.
Fix: use [Link](0.1 + 0.2, 0.3) or the decimal module for financial code.
Interviewer traps — Chapter 2
Trap: bool is a subclass of int — True == 1 and False == 0 (interviewers love this)
Trap: int(9.9) is 9, not 10 — it truncates, not rounds
Trap: 'False' is truthy — non-empty string, regardless of content
Trap: (42) is an int, (42,) is a tuple — trailing comma is critical
Trap: list_b = list_a does NOT copy — they share the same object
12. Corporate Layer
How Senior Developers Use Data Types
• Always use type hints: name: str, price: float, items: list[str]
• Use Decimal for all financial calculations — never float
• Prefer tuples over lists for data that should not change after creation
• Use sets for deduplication and permission checks — O(1) is faster than O(n) list search
• Use [Link](key, default) instead of dict[key] to avoid KeyError in production
Code Review Notes — What Gets Flagged
Code a reviewer will flag Why / What to do instead
if x == None: Use if x is None: — PEP 8 requirement
list_b = list_a Missing copy — use .copy() or [:]
float for money Use Decimal module for currency
No type hints on variables Add type hints, especially in function signatures
dict[key] without guard Use [Link](key) to avoid KeyError
print(0.1 + 0.2) Document the precision limitation or use
Decimal
How a Real API Response Is Typed
When your backend calls the Swiggy or Razorpay API, the response comes back as a dict.
Senior developers immediately map it to typed structures:
Real-world API response handling
from typing import TypedDict, Optional
class OrderItem(TypedDict):
name: str
quantity: int
price: float
class Order(TypedDict):
order_id: str
status: str
items: list[OrderItem]
total: float
customer_name: Optional[str]
# When API returns a raw dict, you annotate it like this:
def process_order(order: Order) -> float:
return sum(item['price'] * item['quantity'] for item in order['items'])
Performance Considerations
• Membership check in set: O(1) — instant. In list: O(n) — slower as list grows
• String concatenation with + in a loop is O(n^2) — use ''.join(list) instead
• Tuple creation is faster than list creation — use tuples for constants
• Dict lookup is O(1) — always prefer dicts over lists for key-based access
13. Practice Problems
Level 1 — Understand
19. Without running code, predict: int(9.99), round(9.99), bool(''), bool('0'), (42) type, (42,)
type
20. List all 8 Python data types. For each, write one real-world example of what it would
store.
21. What is the difference between a list, tuple, and set? Write one sentence for each.
Level 2 — Apply
22. Build a Zomato order system: item name, quantity, unit price (all via input). Calculate
subtotal, GST 18%, delivery fee Rs.40, and print a formatted receipt.
23. Take a comma-separated list of Instagram usernames from input. Print unique
usernames only, sorted alphabetically.
24. Create a PhonePe transaction dict with keys: txn_id, sender, receiver, amount,
timestamp, status. Print it in a readable format.
Level 3 — Build
25. Build a mini Spotify playlist manager: start with a list of 3 songs, let the user add,
remove, and display songs — using list methods only.
26. Build a currency converter: base amount in INR, convert to USD (83.5), EUR (90.2),
GBP (105.4), AED (22.7). Use a dict for rates. Print results formatted to 2 decimal
places.
27. Build a simple contact book using a dict: store 5 contacts (name → phone). Allow lookup
by name. Handle missing contact gracefully.
Level 4 — Explain
28. A junior developer on your team used float for all price calculations. Write a short code
review comment explaining why this is dangerous and what they should use instead.
29. Explain to a non-technical product manager why 'the app shows Rs.999.9999999
instead of Rs.1000' — and what the fix is.
30. Write a comparison of list vs tuple vs set — when to choose each — as if writing internal
team documentation.
14. Mini Project — Razorpay-Style Invoice Generator
This project is Project 2 in the progressive roadmap. It builds directly on the Developer Profile
Card from Chapter 1 and introduces dict, list, float precision, and type conversion working
together.
Concepts used in this project
Variables with type annotations
dict for structured invoice data
list for line items
float → Decimal for precise money math
f-strings with format specifiers
Type conversion: input() → int and float
invoice_generator.py
"""
Razorpay-Style Invoice Generator
Collects line items and generates a formatted invoice with GST.
"""
from decimal import Decimal, ROUND_HALF_UP
GST_RATE: Decimal = Decimal('0.18')
CURRENCY: str = 'Rs.'
def collect_items() -> list[dict]:
"""Collect line items from user input."""
items = []
print('\nEnter invoice items (blank name to finish):')
while True:
name = input(' Item name: ').strip()
if not name:
break
qty = int(input(' Quantity : '))
price = Decimal(input(' Unit price (Rs): '))
[Link]({'name': name, 'qty': qty, 'price': price})
return items
def calculate_totals(items: list[dict]) -> dict:
"""Calculate subtotal, GST, and total."""
subtotal = sum(i['qty'] * i['price'] for i in items)
gst = (subtotal * GST_RATE).quantize(Decimal('0.01'),
rounding=ROUND_HALF_UP)
total = subtotal + gst
return {'subtotal': subtotal, 'gst': gst, 'total': total}
def render_invoice(client: str, items: list[dict], totals: dict) -> None:
"""Print a formatted invoice."""
sep = '=' * 48
print(f'\n{sep}')
print(f' INVOICE')
print(f' Client: {client}')
print(sep)
print(f' {"Item":<20} {"Qty":>5} {"Price":>10} {"Subtotal":>10}')
print('-' * 48)
for item in items:
line_total = item['qty'] * item['price']
print(f" {item['name']:<20} {item['qty']:>5} {CURRENCY}
{item['price']:>9} {CURRENCY}{line_total:>9}")
print(sep)
print(f' Subtotal : {CURRENCY}{totals["subtotal"]:>10}')
print(f' GST 18% : {CURRENCY}{totals["gst"]:>10}')
print(f' TOTAL : {CURRENCY}{totals["total"]:>10}')
print(sep)
if __name__ == '__main__':
client_name = input('Client name: ').strip().title()
line_items = collect_items()
if line_items:
totals = calculate_totals(line_items)
render_invoice(client_name, line_items, totals)
else:
print('No items entered. Invoice cancelled.')
15. Revision Sheet
Concept One-line summary Key trap
int Whole numbers, no size limit int(9.9) = 9, not 10 —
truncates
float Decimal numbers — binary Never use for money: 0.1+0.2
precision issue != 0.3
str Immutable text sequence Operations return new str,
never modify original
bool True/False, subclass of int bool('False') = True — non-
empty string
list Ordered, mutable, allows duplicates list_b = list_a shares object —
use .copy()
tuple Ordered, immutable, allows (42) is int — need (42,) for
duplicates tuple
dict Key-value map, O(1) lookup Use .get(key) not [key] to
avoid KeyError
set Unordered, unique values, O(1) Not subscriptable — no set[0]
check
type() Returns the type of any value Use for debugging, not in
production logic
is vs == is: same object, ==: same value Only use is with None, True,
False
Operator precedence ** before * / before + - Always use () to be explicit
Decimal Precise decimal arithmetic Use for all financial
calculations
16. Cheat Sheet
Chapter 2 — Data Types & Operators Quick Reference
# TYPE CHECKING
type(42) # <class 'int'>
isinstance(42, int) # True
# TYPE CONVERSION
int('25') float('3.14') str(100) bool(0)
list('hello') set([1,2,2,3]) tuple([1,2])
# STRING
s = 'Netflix'
s[0] s[-1] s[2:5] s[::-1] # index / slice
[Link]() .upper() .lower() .title()
[Link](',') ','.join(list) # split and join
f'{value:.2f}' f'{n:,}' f'{p:.1%}' # f-string formats
# LIST
[Link](x) [Link](i,x) [Link](x) [Link]()
[Link]() sorted(lst) len(lst) x in lst
[Link]() or lst[:] # safe copy
# DICT
[Link](key) [Link](key, default)
[Link]() [Link]() [Link]()
[Link](other) [Link](key, 0)
{k: v for k, v in [Link]() if v > 100} # dict comprehension
# SET
s & t # intersection s | t # union
s - t # difference s ^ t # symmetric diff
# OPERATORS
// # floor div % # modulus ** # power
and or not is is not in not in
# MONEY — always use Decimal
from decimal import Decimal
total = Decimal('999.99') + Decimal('0.01') # 1000.00 exactly
End of Chapter 2
Next: Chapter 3 — Control Flow: if, elif, else, match-case
You now know what kind of thing every value is, how to transform it,
and how to operate on it correctly. That is the foundation every Python
developer builds on for the rest of their career. Chapter 3 awaits.