undefined
Home About lightbulbSkillUp Projects Contact Us
Client Login

Data Types & Structures Loops & Control Flows

Programming foundation - Storing and working with different kinds of data

Variables in Python are symbolic names pointing to objects or values in memory. Unlike many other languages, Python has no command for declaring a variable — a variable is created the moment you first assign a value to it.

Python has several built-in data types. Understanding when to use each type is fundamental to writing effective Python code.

Numeric Data Types

Python has three numeric types:

  • int — whole numbers with no size limit: 42, -7, 1_000_000
  • float — 64-bit decimal numbers: 3.14, 2.5e3 (= 2500.0)
  • complex — real + imaginary: 3 + 4j

Key built-in functions:

  • abs(x) — absolute value
  • round(x, n) — round to n decimal places
  • pow(x, y) — same as x ** y
  • divmod(x, y) — returns (quotient, remainder) as a tuple
  • int(x), float(x), str(x) — type conversion

Note: int(3.9) gives 3 — it truncates, it does not round.

Python
# ── int ──────────────────────────────────────────────────────x = 42big  = 1_000_000      # underscores improve readabilitybin_ = 0b1010         # binary literal  → 10hex_ = 0xFF           # hex literal     → 255print(x, big, bin_, hex_) # ── float ─────────────────────────────────────────────────────pi  = 3.14159sci = 2.5e3           # scientific notation → 2500.0print(pi, sci) # ── complex ───────────────────────────────────────────────────c = 3 + 4jprint(c.real, c.imag) # 3.0  4.0print(abs(c))         # 5.0  (magnitude √(3²+4²)) # ── type conversion ───────────────────────────────────────────print(int(3.9))       # 3   ← truncates, does NOT roundprint(float(7))       # 7.0print(str(42))        # '42'print(bool(0))        # Falseprint(bool(-5))       # True # ── useful built-ins ──────────────────────────────────────────print(abs(-15))            # 15print(round(3.14159, 2))   # 3.14print(pow(2, 10))          # 1024print(divmod(17, 5))       # (3, 2)  quotient and remainderprint(max(3, 7, 1, 9))     # 9print(min(3, 7, 1, 9))     # 1

String Data Type

Strings are immutable sequences of characters. All string methods return a new string — they never modify the original.

Use single '...' or double "..." quotes. Triple quotes """...""" span multiple lines.

Case & whitespace: upper(), lower(), title(), strip(), lstrip(), rstrip()

Search: find(s) → index or -1, count(s), startswith(s), endswith(s)

Test: isdigit(), isalpha(), isalnum(), isspace()

Modify: replace(old, new), split(sep), join(iterable)

Format: f-strings f"..." — embed any expression inside {}

Python
s = "  Hello, Python World!  " # ── case & whitespace ─────────────────────────────────────────print(s.strip())          # "Hello, Python World!"print(s.lower())print(s.upper())print("hElLo".swapcase()) # "HeLlO" # ── search ────────────────────────────────────────────────────t = "Hello, Python World!"print(t.find("Python"))       # 7  (index; -1 if not found)print(t.count("l"))           # 3print(t.startswith("Hello"))  # Trueprint(t.endswith("!"))        # True # ── test ──────────────────────────────────────────────────────print("123".isdigit())    # Trueprint("abc".isalpha())    # Trueprint("abc123".isalnum()) # True # ── modify ────────────────────────────────────────────────────print(t.replace("Python", "Data Science"))print("a,b,c,d".split(","))           # ['a', 'b', 'c', 'd']print("-".join(["2024", "01", "15"]))  # '2024-01-15' # ── f-strings ─────────────────────────────────────────────────name  = "Alice"score = 98.567print(f"{name} scored {score:.2f}%")   # Alice scored 98.57%print(f"{'Python':^20}")               # centred in 20 charsprint(f"{42:08b}")                     # 00101010 (binary)

Indexing & Slicing

Python uses zero-based indexing. Negative indices count from the right (-1 is the last element).

Slice syntax: seq[start : stop : step]stop is always exclusive. Use -1 as step to reverse. Works on strings, lists, and tuples.

Python
text = "Python"nums = [10, 20, 30, 40, 50] # ── indexing ──────────────────────────────────────────────────print(text[0], text[-1])    # P  nprint(nums[2], nums[-2])    # 30  40 # ── slicing strings ───────────────────────────────────────────print(text[0:3])   # Pytprint(text[2:])    # thonprint(text[:3])    # Pytprint(text[::2])   # Pto   every 2nd charprint(text[::-1])  # nohtyP  reversed # ── slicing lists ─────────────────────────────────────────────print(nums[1:4])   # [20, 30, 40]print(nums[::2])   # [10, 30, 50]print(nums[::-1])  # [50, 40, 30, 20, 10] # ── slicing returns a NEW object ──────────────────────────────subset = nums[1:3]print(subset)      # [20, 30]print(nums)        # [10, 20, 30, 40, 50]  unchanged

Lists

A list is an ordered, mutable sequence. You can add, remove, and change elements after creation.

Add: append(x), insert(i, x), extend(iterable)

Remove: remove(x) by value, pop(i) by index (returns the item), clear()

Search: index(x) → first position, count(x) → occurrences

Order: sort() modifies in place; sorted(lst) returns a new sorted list

Copy: copy() — without it, two variables share the same list object.

Python
fruits = ["apple", "banana", "cherry"] # ── add ───────────────────────────────────────────────────────fruits.append("date")                 # add to endfruits.insert(1, "avocado")           # insert at index 1fruits.extend(["elderberry", "fig"])  # add multipleprint(fruits) # ── remove ────────────────────────────────────────────────────fruits.remove("avocado")   # remove by value (first match)popped = fruits.pop()      # remove & return last itemprint(f"Popped: {popped}") # ── search ────────────────────────────────────────────────────nums = [3, 1, 4, 1, 5, 9, 2, 6]print(nums.index(4))    # 2print(nums.count(1))    # 2 # ── sort ──────────────────────────────────────────────────────nums.sort()             # in placeprint(nums)words = ["banana", "apple", "cherry"]print(sorted(words))    # new list  — original unchangedprint(words) # ── mutability: two names, same list ─────────────────────────a = [1, 2, 3]b = ab.append(4)print(a)        # [1, 2, 3, 4]  ← also changed!c = a.copy()    # independent copyc.append(99)print(a)        # [1, 2, 3, 4]  ← unchanged

Tuples

A tuple is an ordered, immutable sequence. Once created, you cannot add, remove, or change elements. A single-element tuple needs a trailing comma: (42,).

Use tuples for: coordinates, RGB values, function returns, and dictionary keys (lists cannot be keys).

Tuple unpacking assigns multiple variables in one line. Use * to capture remaining elements.

Python
# ── creating tuples ───────────────────────────────────────────point  = (3, 7)rgb    = (255, 128, 0)single = (42,)       # trailing comma required! # ── access ────────────────────────────────────────────────────print(point[0])     # 3print(rgb[-1])      # 0print(rgb[0:2])     # (255, 128) # ── unpacking ─────────────────────────────────────────────────x, y = pointprint(f"x={x}, y={y}") r, g, b = rgbprint(f"R={r} G={g} B={b}") first, *rest = (1, 2, 3, 4, 5)print(first, rest)   # 1  [2, 3, 4, 5] # ── immutable ─────────────────────────────────────────────────try:    point[0] = 10except TypeError as e:    print(f"TypeError: {e}") # ── tuple as dict key ─────────────────────────────────────────loc = {(28.6, 77.2): "Delhi", (19.1, 72.9): "Mumbai"}print(loc[(28.6, 77.2)])   # Delhi # ── count & index ─────────────────────────────────────────────t = (1, 2, 2, 3, 2)print(t.count(2), t.index(3))   # 3  3

Dictionaries

A dictionary stores key-value pairs. Keys must be unique and immutable. Dicts are mutable and, since Python 3.7, preserve insertion order.

Use d.get(key, default) instead of d[key] when the key might be absent — it returns None (or a default) instead of raising a KeyError.

Views: keys(), values(), items() — live views, not copies.

Python
person = {"name": "Alice", "age": 28, "city": "Jaipur"} # ── access ────────────────────────────────────────────────────print(person["name"])             # Aliceprint(person.get("salary"))      # None  (no KeyError)print(person.get("salary", 0))   # 0     (default) # ── add / update ──────────────────────────────────────────────person["email"] = "alice@example.com"person["age"]   = 29person.update({"city": "Delhi", "role": "analyst"})print(person) # ── remove ────────────────────────────────────────────────────removed = person.pop("email")print(f"Removed: {removed}") # ── iterate ───────────────────────────────────────────────────for key, value in person.items():    print(f"  {key}: {value}") # ── membership check ──────────────────────────────────────────print("name"   in person)   # Trueprint("salary" in person)   # False # ── setdefault ────────────────────────────────────────────────person.setdefault("country", "India")print(person["country"])    # India

for Loops & range()

The for loop iterates over any iterable — lists, tuples, strings, dicts, and range objects.

range(): range(n) → 0 to n−1  |  range(start, stop) → stop is exclusive  |  range(start, stop, step)

Extras: enumerate(iterable) yields (index, value) pairs; zip(a, b) pairs two iterables element by element.

Python
# ── range variants ────────────────────────────────────────────for i in range(5):          print(i, end=" ")   # 0 1 2 3 4print()for i in range(1, 6):       print(i, end=" ")   # 1 2 3 4 5print()for i in range(0, 20, 5):   print(i, end=" ")   # 0 5 10 15print()for i in range(10, 0, -2):  print(i, end=" ")   # 10 8 6 4 2print() # ── iterating a list and string ───────────────────────────────fruits = ["apple", "banana", "cherry"]for fruit in fruits:    print(fruit.upper()) for char in "Python":    print(char, end="-")   # P-y-t-h-o-n-print() # ── enumerate: index + value ──────────────────────────────────for i, fruit in enumerate(fruits, start=1):    print(f"{i}. {fruit}") # ── zip: pair two lists ───────────────────────────────────────names  = ["Alice", "Bob", "Charlie"]scores = [92, 85, 78]for name, score in zip(names, scores):    print(f"{name}: {score}") # ── iterating a dictionary ────────────────────────────────────grades = {"Maths": "A", "Science": "B", "English": "A"}for subject, grade in grades.items():    print(f"{subject} → {grade}")

while Loops

A while loop runs as long as its condition is True. Use it when you don't know the number of iterations in advance.

while-else: the else block runs when the condition becomes False naturally — it is skipped if a break exits the loop.

Python
# ── basic while ───────────────────────────────────────────────count = 1while count <= 5:    print(f"Count: {count}")    count += 1print("Done!") # ── countdown ─────────────────────────────────────────────────n = 10while n > 0:    print(n, end=" ")    n -= 3print(f"\nFinal n: {n}") # ── while-else ────────────────────────────────────────────────attempts = 0while attempts < 3:    attempts += 1    print(f"Attempt {attempts}")else:    print("All attempts used")   # runs when loop ends naturally # ── search (break skips the else) ─────────────────────────────items  = [4, 7, 2, 9, 1, 5]target = 9i = 0while i < len(items):    if items[i] == target:        print(f"Found {target} at index {i}")        break    i += 1else:    print(f"{target} not found")   # skipped because break fired

break, continue & pass

Three statements give fine-grained control inside any loop:

  • breakexit the loop immediately; skips the else clause
  • continueskip the rest of the current iteration and move to the next
  • passdo nothing; placeholder for an empty block while drafting code
Python
# ── break ─────────────────────────────────────────────────────print("-- break --")for i in range(1, 10):    if i == 5:        print("Reached 5, stopping!")        break    print(i)              # prints 1 2 3 4 # ── continue ──────────────────────────────────────────────────print("-- continue --")for i in range(1, 8):    if i % 2 == 0:        continue          # skip even numbers    print(i)              # prints 1 3 5 7 # ── pass ──────────────────────────────────────────────────────print("-- pass --")for i in range(5):    if i == 2:        pass              # placeholder — handle later    else:        print(i)          # prints 0 1 3 4 # ── break + else pattern ──────────────────────────────────────numbers = [3, 7, 12, 5, 8]for num in numbers:    if num > 10:        print(f"First > 10: {num}")        breakelse:    print("None greater than 10")   # runs only if no break

List Comprehension

List comprehension creates a list from an iterable in a single, readable expression — faster and more concise than a for-loop + append.

Syntax: [expression  for item in iterable  if condition] — the if part is optional.

Python
# ── basic ─────────────────────────────────────────────────────squares = [x**2 for x in range(1, 6)]print(squares)     # [1, 4, 9, 16, 25] # ── with condition ────────────────────────────────────────────evens = [x for x in range(20) if x % 2 == 0]print(evens)       # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] # ── transform strings ─────────────────────────────────────────words = ["hello", "world", "python"]upper = [w.upper() for w in words]print(upper)       # ['HELLO', 'WORLD', 'PYTHON'] # ── filter AND transform ──────────────────────────────────────fruits = ["apple", "Banana", "cherry", "Date", "elderberry"]long_lower = [f.lower() for f in fruits if len(f) > 5]print(long_lower)  # ['banana', 'cherry', 'elderberry'] # ── equivalent for-loop (more verbose) ────────────────────────result = []for f in fruits:    if len(f) > 5:        result.append(f.lower())print(result)      # same result # ── nested: flatten a 2D list ─────────────────────────────────matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]flat   = [num for row in matrix for num in row]print(flat)        # [1, 2, 3, 4, 5, 6, 7, 8, 9]

Mutability

Mutability determines whether an object can be changed after creation.

Immutable (cannot be modified in place): int, float, complex, bool, str, tuple

Mutable (can be modified in place): list, dict, set

Shared reference trap: assigning a mutable object to two variables makes both point to the same object. Use .copy() (or copy.deepcopy() for nested structures) for an independent copy.

Python
# ── immutable int: reassignment creates a NEW object ─────────x = 10y = xx = 20print(y)        # 10  — y unaffected # ── immutable str: methods return a new string ───────────────s = "hello"t = ss = s.upper()   # s → "HELLO" (new object)print(t)        # "hello"  — t unchanged # ── mutable list: shared reference ────────────────────────────a = [1, 2, 3]b = a           # b is NOT a copy!b.append(4)print(a)        # [1, 2, 3, 4]  ← a also changed # ── fix with .copy() ──────────────────────────────────────────c = a.copy()c.append(99)print(a)        # [1, 2, 3, 4]  ← unchangedprint(c)        # [1, 2, 3, 4, 99] # ── mutable dict: same shared-reference behaviour ────────────d1 = {"x": 1}d2 = d1d2["y"] = 2print(d1)       # {'x': 1, 'y': 2}  ← shared! # ── immutable tuple ───────────────────────────────────────────try:    (1, 2, 3)[0] = 99except TypeError as e:    print(f"TypeError: {e}") print("Mutable  :", ["list", "dict", "set"])print("Immutable:", ["int", "float", "str", "tuple", "bool"])
code Python REPL — Try it yourself

        

Practice Questions

Question 1

What is the result of 10 // 3 in Python?

Question 2

What does "Python"[-1] return?

Question 3

What is the output of "abcdef"[1:4]?

Question 4

What does [1, 2, 3].append(4) return?

Question 5

Which of the following will raise a TypeError?

Question 6

How do you safely access a dictionary key that might not exist (without raising KeyError)?

Question 7

What does list(range(2, 10, 3)) produce?

Question 8

What happens when break is encountered inside a for loop?

Question 9

What is printed by: for i in range(5):\n if i == 2: continue\n print(i, end=' ')

Question 10

What is the purpose of 'pass' in Python?

Question 11

What does [x**2 for x in range(1, 6)] produce?

Question 12

Which of the following is immutable in Python?