0% found this document useful (0 votes)
2 views28 pages

Think in Python Chapter2

Chapter 2 of 'Think in Python' focuses on variables, data types, and operators, emphasizing their importance in programming. It discusses common pitfalls, such as type errors, and introduces Python's built-in data types, including int, float, str, bool, list, tuple, dict, and set. The chapter also covers variable naming conventions, multiple assignment, and the mutable versus immutable nature of data types.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views28 pages

Think in Python Chapter2

Chapter 2 of 'Think in Python' focuses on variables, data types, and operators, emphasizing their importance in programming. It discusses common pitfalls, such as type errors, and introduces Python's built-in data types, including int, float, str, bool, list, tuple, dict, and set. The chapter also covers variable naming conventions, multiple assignment, and the mutable versus immutable nature of data types.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

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.

You might also like