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)