DEV Community

Tejas Shinkar
Tejas Shinkar

Posted on

while Loop, break & continue, Lists (Creation, Mutability, Methods, List Comprehension)

📌 Key Concepts Overview

Concept One-Line Definition
while loop Repeats code as long as a condition is True
while True Infinite loop — needs break to stop
break Immediately exits the loop
continue Skips current iteration, moves to next
List Ordered, mutable collection — heterogeneous elements allowed
List Comprehension One-line way to build a list using a loop + condition
List Mutability Lists can be changed in place — id() stays the same

🔁 Part 1 — while Loop

The 3 Components (Critical Pattern)

# 1. Initialisation  2. Condition  3. Increment/Decrement

a = 1                  # 1. Initialisation
while a <= 10:          # 2. Condition
    print('Devops')
    a += 1              # 3. Increment

# Without increment → INFINITE LOOP (condition never becomes False)
Enter fullscreen mode Exit fullscreen mode

How it works: Condition is checked before each iteration. As soon as it's False, the loop stops. Miss the increment/decrement → infinite loop (a real production hazard — can hang a script or burn CPU).

while — Practical Patterns

# Countdown (decrement)
a = 10
while a > 0:
    print('Devops')
    a -= 1

# Sum of 1 to 20
total = 0
a = 1
while a <= 20:
    total += a
    a += 1
print(total)        # 210

# Product (factorial-style) of 1 to 20
product = 1
a = 1
while a <= 20:
    product *= a
    a += 1
print(product)

# Pattern using while + string repetition
str1 = 'Devops'
i = 0
while i < len(str1):
    print(str1[i] * (i + 1))
    i += 1
# D
# ee
# vvv
# oooo
# ppppp
# ssssss
Enter fullscreen mode Exit fullscreen mode

for vs while — When to Use Which

Use for Use while
You know the iterable / number of repetitions You don't know how many times — depends on a condition
Looping over list, string, range Retry logic, polling, waiting for a state
# DevOps: retry logic — classic while True use case
max_attempts = 5
attempt = 0
while attempt < max_attempts:
    print(f'Attempt {attempt+1}: Connecting to server...')
    # if connection succeeds: break
    attempt += 1
Enter fullscreen mode Exit fullscreen mode

while True — Infinite Loop Pattern

# Always True — runs forever until break is hit
# Used for: retry logic, polling, menu-driven scripts, password validation

password = 'xyz1234'
p = input('Enter your password: ')
while True:
    if p == password:
        print('Password matched')
        break                          # exits the loop
    else:
        print('Incorrect password. Try again')
        p = input('Enter your password: ')
Enter fullscreen mode Exit fullscreen mode

DevOps real use: polling an AWS resource until it reaches running state, retrying an API call until success, watching a deployment status.

# Simulated polling pattern (real-world shape)
status = 'pending'
checks = 0
while True:
    checks += 1
    print(f'Check #{checks}: status = {status}')
    if status == 'running':
        print('✅ Instance is up')
        break
    if checks >= 5:
        print('❌ Timeout waiting for instance')
        break
    # status = check_instance_status()   # in real code
    status = 'running' if checks == 3 else 'pending'   # simulate
Enter fullscreen mode Exit fullscreen mode

⏭️ Part 2 — Transfer Statements: break & continue

break — Exit the Loop Entirely

lst = [1, 37, 'Python', True, None, 'Devops', 38, 483, 38.438]

# Print elements until None is found, then stop
for i in lst:
    if i == None:
        break
    else:
        print(i)
# Output: 1, 37, Python, True   (stops at None)
Enter fullscreen mode Exit fullscreen mode

continue — Skip Current Iteration Only

lst = [1, 37, None, 'Python', True, None, 'Devops', 38, 483, None, 38.438]

# Skip None values, but KEEP looping through the rest
for i in lst:
    if i == None:
        continue          # skip this iteration, move to next
    else:
        print(i)
# Output: 1, 37, Python, True, Devops, 38, 483, 38.438   (all non-None values)
Enter fullscreen mode Exit fullscreen mode

The Key Difference:

Statement Effect Loop continues?
break Stops the loop completely ❌ No — exits
continue Skips just this one iteration ✅ Yes — moves to next

break in Nested Loops — Only Breaks the Inner Loop

lst = ['peter', 'piper', 'picked']

# break in inner loop only — outer loop continues
for word in lst:
    for char in word:
        print(char)
        break              # breaks INNER loop only — prints first char of each word
# p, p, p   (first letter of each word)

# break in outer loop — stops everything after first word
for word in lst:
    for char in word:
        print(char)
    break                  # breaks OUTER loop — only processes 'peter'
# p, e, t, e, r

# break in both — exits after just ONE character total
for word in lst:
    for char in word:
        print(char)
        break
    break
# p   (only)
Enter fullscreen mode Exit fullscreen mode

⚠️ Critical for interviews: break/continue only affects the loop they're directly inside — not outer loops.


📦 Part 3 — Lists Deep Dive

List Basics

# Heterogeneous — any mix of types allowed
lst = [1, 37, None, 'Python', True, None, 'Devops', 38, 483, None, 38.438]
print(lst, type(lst))
Enter fullscreen mode Exit fullscreen mode

List Operations

# Concatenation — combine two lists
lst = [1, 2, 3, 4, 5]
lst1 = [6, 7, 8, 9, 10]
print(lst + lst1)             # [1,2,3,4,5,6,7,8,9,10]

# ⚠️ + does NOT modify in place — must reassign
lst + [50]
print(lst)                    # unchanged! still [1,2,3,4,5]
lst = lst + [50]              # ✅ now it's updated

# ❌ Can't add a list and a non-iterable directly
# lst + 50   → TypeError: can only concatenate list (not "int") to list

# Repetition
lst = [1, 2, 3, 4, 5]
print(lst * 5)                # repeats the whole list 5 times

# Length
print(len(lst))                # 5

# Indexing
print(lst[2])                  # 3rd element (0-indexed)

# Slicing
print(lst[::1])                 # full copy, same order
print(lst[::-1])                # reversed list
Enter fullscreen mode Exit fullscreen mode

Nested Lists & Deep Indexing

lst = [37, 'Python', 23+37j, True, [1, 36, 'Devops'],
       [['Linux', 'AWS', 'Learnbay'], 73, 73.476, 51, 'Hello'],
       'Sunday', 'weekend',
       ['Hello', ['hey', 'WFH', [37, 26.437, False], 'Functions']]]

print(lst[5][4])      # 'Hello' — index 5 → that sub-list → index 4
print(lst[8][1][2][1])  # drilling 4 levels deep

# DevOps relevance: nested JSON/API responses look exactly like this
# e.g., ec2_response['Reservations'][0]['Instances'][0]['State']['Name']
Enter fullscreen mode Exit fullscreen mode

Mutability — The Core List Property

lst = [1, 2, 3, 4, 5]
print(id(lst))           # e.g. 140234...

lst[2] = 'Python'        # modify in place — item assignment
print(lst)               # [1, 2, 'Python', 4, 5]
print(id(lst))           # SAME id — list was modified, not recreated
Enter fullscreen mode Exit fullscreen mode

Why this matters: Lists are mutable — changing them doesn't create a new object. This is different from strings/tuples (immutable), where any "change" actually creates a brand-new object.


🏗️ Ways to Create a List

# Case 1 — Direct literal (when you know elements)
lst = [1, 2, 34, 5, 6, 'python', True]

# Case 2 — Using list() on an iterable
list('Python')              # ['P','y','t','h','o','n']
list((10, 20, 30, 40))      # from a tuple → [10,20,30,40]
list(range(12, 24))         # from a range → [12,13,...,23]
list(input('Enter: '))      # from input string → char by char list

# ⚠️ list() on a single non-iterable-wrapped value vs a list with one item
list(['Python'])            # ['Python']  — already a list with 1 string
list('Python')              # ['P','y','t','h','o','n']  — string exploded char by char

# Case 3 — List Comprehension (most DevOps-relevant!)
# Syntax: [expression for item in iterable if condition]

lst = [i for i in range(1, 11)]                     # [1,2,...,10]
lst = [i**2 for i in range(1, 21) if i % 2 == 0]    # squares of even numbers 1-20

# Compare to the manual for-loop equivalent:
lst = []
for i in range(1, 11):
    lst += [i]
# vs the one-liner:
lst = [i for i in range(1, 11)]
Enter fullscreen mode Exit fullscreen mode

🛠️ List Methods — Full Reference

dir(lst)    # shows all available methods on a list object
Enter fullscreen mode Exit fullscreen mode

append() — Add ONE Item to the End

lst = [1, 2, 3, 4, 5]
lst.append(30)              # [1,2,3,4,5,30]
lst.append([30, 50])        # adds the WHOLE list as ONE nested item
                             # [1,2,3,4,5,30,[30,50]]  ⚠️ not flattened!
lst.append('Python')        # adds as a single string element

# ❌ append() only takes ONE argument
# lst.append(30, 50)   → TypeError
Enter fullscreen mode Exit fullscreen mode

extend() — Add Items One-by-One (Flatten an Iterable In)

lst = [100, 200, 300, 400, 500]
lst.extend('Python')        # adds each CHARACTER separately
print(lst)                  # [100,200,300,400,500,'P','y','t','h','o','n']

lst = [1, 2, 3, 4, 5]
lst.extend([30, 50])        # adds each element separately
print(lst)                  # [1,2,3,4,5,30,50]
Enter fullscreen mode Exit fullscreen mode

append() vs extend() — THE classic interview question:

Method Adds Example
append(x) x as a single element (even if x is a list) lst.append([1,2])[...,[1,2]]
extend(x) each element of x individually lst.extend([1,2])[...,1,2]

insert() — Insert at a Specific Index

# lst.insert(index, value)
lst = [1, 37, None, 'Python', True]
lst.insert(2, 'Sunday')      # inserts BEFORE index 2, shifts rest right
print(lst)                   # [1, 37, 'Sunday', None, 'Python', True]

lst.insert(-2, 'Python')     # works with negative indexing too
Enter fullscreen mode Exit fullscreen mode

count() — Count Occurrences

lst = [1, 2, 3, 1, 2, 3, 1, 2, 3]
print(lst.count(2))          # 3
print(lst.count(1))          # 3
Enter fullscreen mode Exit fullscreen mode

index() — Find Position of First Occurrence

lst = [1, 2, 3, 1, 2, 3]
print(lst.index(2))          # 1 (first occurrence, left to right)
print(lst.index(20))         # ❌ ValueError: 20 is not in list
Enter fullscreen mode Exit fullscreen mode

pop() — Remove by Index (Returns the Removed Value)

# lst.pop(index)  — default removes the LAST item
lst = [100, 200, 300, 400, 500]
removed = lst.pop(2)          # removes index 2 → returns 300
print(removed)                # 300
print(lst)                    # [100,200,400,500]

lst.pop()                     # removes LAST item by default
lst.pop(-2)                   # negative indexing works too

# ❌ Invalid index → IndexError: pop index out of range
Enter fullscreen mode Exit fullscreen mode

remove() — Remove by VALUE (Not Index)

# lst.remove(value) — removes FIRST occurrence, returns nothing
lst = [100, 200, 300, 400, 300, 500]
lst.remove(300)               # removes the FIRST 300 only
print(lst)                    # [100,200,400,300,500]

# ❌ Value not in list → ValueError
Enter fullscreen mode Exit fullscreen mode

pop() vs remove() — Interview Favourite:

Method Removes by Returns Error if missing
pop(index) position/index the removed value IndexError
remove(value) the value itself None ValueError

reverse() — Reverses In Place

lst = [1, 2, 3, 4, 5]
lst.reverse()
print(lst)        # [5,4,3,2,1] — modifies original list
Enter fullscreen mode Exit fullscreen mode

sort() — Sorts In Place (Ascending by Default)

lst = [72, 48, 216, 4873, 462, 9]
lst.sort()                    # ascending
lst.sort(reverse=True)        # descending

# Works on strings too (alphabetical / ASCII order)
lst = list('coiuhihcbciygdhs')
lst.sort()

# ⚠️ sort() FAILS on mixed/heterogeneous types
lst = [1, 'Python', True, 38.438]
# lst.sort()   → TypeError: can't compare str and int
Enter fullscreen mode Exit fullscreen mode

clear() — Empty the List (Same Object, Same id())

lst = [1, 37, 'Python', True]
print(id(lst))
lst.clear()
print(lst)            # []
print(id(lst))        # SAME id — emptied in place, not a new object
Enter fullscreen mode Exit fullscreen mode

copy() — Create an Independent Copy (CRITICAL CONCEPT)

# ❌ WITHOUT copy() — both variables point to the SAME list (same id)
lst = [1, 2, 3, 4, 5]
lst1 = lst                    # NOT a copy — just another name for the same object
lst1[2] = 93
print(lst1)                   # [1,2,93,4,5]
print(lst)                    # [1,2,93,4,5]  ⚠️ original also changed!

# ✅ WITH copy() — independent list, different id
lst = [1, 2, 3, 4, 5]
lst1 = lst.copy()             # new object, different id
lst1[2] = 93
print(lst1)                   # [1,2,93,4,5]
print(lst)                    # [1,2,3,4,5]  ✅ original untouched
Enter fullscreen mode Exit fullscreen mode

This is one of the most important bugs to understand in Python. lst1 = lst does NOT copy — it just creates a second reference to the exact same list in memory.

Manual String Split (Building Towards .split())

# Class built this manually to understand the LOGIC behind str.split()
str1 = 'Peter piper picked a pack of pickeled peppers'

lst = []
res = ''
for char in str1:
    if char != ' ':
        res += char
    else:
        lst.append(res)
        res = ''
lst.append(res)          # don't forget the last word!
print(lst)
# ['Peter', 'piper', 'picked', 'a', 'pack', 'of', 'pickeled', 'peppers']

# This is literally what str.split() does internally:
print(str1.split())      # same result, one line
Enter fullscreen mode Exit fullscreen mode

☁️ DevOps / Cloud Use Cases

# 1. Poll AWS instance status until running (while True pattern)
status = 'pending'
attempts = 0
while True:
    attempts += 1
    if status == 'running':
        print('✅ Instance ready')
        break
    if attempts > 10:
        print('❌ Timeout — instance not ready')
        break
    # status = get_instance_status()   # real AWS SDK call

# 2. Retry failed deployment with break on success
max_retries = 3
attempt = 0
while attempt < max_retries:
    attempt += 1
    print(f'Deploy attempt {attempt}...')
    success = (attempt == 2)        # simulated
    if success:
        print('✅ Deployed')
        break
else:
    print('❌ All retries failed')

# 3. Filter out failed health checks using continue
servers_status = ['ok', 'fail', 'ok', None, 'ok', 'fail']
for status in servers_status:
    if status is None or status == 'fail':
        continue
    print(f'✅ Server status: {status}')

# 4. Build list of running instance IDs with list comprehension
instances = [
    {'id': 'i-001', 'state': 'running'},
    {'id': 'i-002', 'state': 'stopped'},
    {'id': 'i-003', 'state': 'running'},
]
running_ids = [inst['id'] for inst in instances if inst['state'] == 'running']
print(running_ids)        # ['i-001', 'i-003']

# 5. extend() to merge server lists from multiple regions
us_servers = ['web-us-1', 'web-us-2']
eu_servers = ['web-eu-1', 'web-eu-2']
all_servers = []
all_servers.extend(us_servers)
all_servers.extend(eu_servers)
print(all_servers)

# 6. copy() before modifying a shared config list
base_ports = [22, 80, 443]
web_ports = base_ports.copy()
web_ports.append(8080)
print(base_ports)         # unaffected — still [22, 80, 443]
print(web_ports)          # [22, 80, 443, 8080]
Enter fullscreen mode Exit fullscreen mode

❌ Common Mistakes

Mistake Code Fix
Forgetting increment in while while a<=10: print(a) (no a+=1) Infinite loop — always increment/decrement
lst + [x] doesn't modify list lst + [50] then expects lst changed Reassign: lst = lst + [50]
append() vs extend() confusion lst.append([1,2]) → adds nested list, not 2 items Use extend() to flatten in
lst1 = lst thinking it's a copy Modifying lst1 also changes lst Use lst1 = lst.copy()
sort() on mixed types [1,'a',True].sort() TypeError — sort only same-type lists
pop() on empty/invalid index [].pop() IndexError — check length first
remove() on missing value lst.remove(999) when not present ValueError — check in first
break only exits ONE loop level Expecting break to exit nested loops fully Need a flag or function return for full exit

🎯 Interview Points

  1. "Difference between append() and extend()?"
    append() adds its argument as a single element (even a whole list becomes one nested item). extend() iterates through its argument and adds each element individually.

  2. "Difference between break and continue?"
    break exits the loop entirely. continue skips only the current iteration and proceeds to the next one.

  3. "Difference between pop() and remove()?"
    pop(index) removes by position and returns the value; default removes the last item. remove(value) removes the first matching value and returns nothing.

  4. "What happens when you do lst1 = lst vs lst1 = lst.copy()?"
    lst1 = lst makes lst1 point to the SAME object — changes to one affect the other. .copy() creates an independent object with a new id().

  5. "Why are lists mutable?"
    → Their contents can be changed after creation (id() stays the same) — unlike strings/tuples where any change creates a new object.

  6. "What's a list comprehension and why use it?"
    → A concise one-line way to build a list: [expr for item in iterable if condition]. More Pythonic and often faster than a manual for-loop + append.

  7. "When would you use while True over a regular while?"
    → When the exit condition is checked INSIDE the loop body rather than at the top — e.g., retry logic, polling, "ask again until valid input."


📚 Knowledge Base — Quick Revision

# ── WHILE LOOP ──────────────────────────────────────────────
a = 1                       # 1. init
while a <= 10:               # 2. condition
    ...
    a += 1                    # 3. increment — NEVER forget this

while True:                  # infinite — needs break
    if condition:
        break

# ── BREAK / CONTINUE ────────────────────────────────────────
break        # exits the loop entirely
continue     # skips current iteration, loop continues

# ── LIST CREATION ───────────────────────────────────────────
lst = [1, 2, 3]                       # literal
lst = list('abc')                     # from string → ['a','b','c']
lst = list(range(5))                  # from range
lst = [i for i in range(10)]          # comprehension
lst = [i**2 for i in range(10) if i%2==0]   # comprehension + filter

# ── LIST OPERATIONS ─────────────────────────────────────────
lst + lst2          # concatenation (new list, must reassign)
lst * 3              # repetition
len(lst)              # length
lst[i]                # indexing
lst[::-1]             # reverse via slicing

# ── LIST METHODS (mutating, in-place) ───────────────────────
lst.append(x)         # add ONE item to end
lst.extend(iterable)  # add items individually
lst.insert(i, x)      # insert before index i
lst.pop(i)            # remove by index, RETURNS value (default: last)
lst.remove(x)         # remove by VALUE, first match, returns None
lst.reverse()         # reverse in place
lst.sort()            # ascending; sort(reverse=True) for descending
lst.clear()           # empty the list (same id)
lst.count(x)          # occurrences of x
lst.index(x)          # first index of x (ValueError if missing)
lst.copy()            # independent shallow copy (new id)

# ── CRITICAL GOTCHA ─────────────────────────────────────────
lst1 = lst             # ❌ same object — NOT a copy
lst1 = lst.copy()      # ✅ independent copy
Enter fullscreen mode Exit fullscreen mode

🏋️ Practice Questions

Easy

  1. Write a while loop that prints numbers from 10 down to 1.
  2. Given lst = [10, 20, 30, 40, 50], use append() to add 60, then extend() to add [70, 80]. Print the list after each step.
  3. Use a list comprehension to create a list of cubes (x³) for numbers 1 to 10.

Medium

  1. Write a while True loop that keeps asking the user to enter a number until they enter a number greater than 100, then breaks and prints "Valid number entered."
  2. Given lst = [5, 10, None, 15, None, 20], write a loop using continue to print only non-None values, and a separate loop using break to print values until the first None.
  3. Demonstrate the lst1 = lst vs lst1 = lst.copy() bug with code: create a list, assign it without .copy(), modify the copy, and show the original also changed. Then fix it using .copy().

DevOps-Focused

  1. Retry Connector: Write a while loop that simulates connecting to a server. It should try up to 5 times. Use a variable connected = False that becomes True on the 3rd attempt (simulated). Print each attempt, and break with a success message once connected, or a failure message after 5 failed attempts.
  2. Server List Builder: You have two lists: prod_servers = ['web-01','web-02'] and staging_servers = ['stg-01','stg-02']. Use extend() to build one combined all_servers list. Then use a list comprehension to create prod_only containing only servers that start with 'web'. Print both results.

Top comments (0)