Previous | Tutorial index | Next

Tutorial 6: Augmented Assignment Statements

Learning Objective

To be able to write augmented assignment statements.

1. Overview of Augmented Assignment Statements

1.1 What are Augmented Assignments?

Augmented assignments are a shorthand notation that combines an arithmetic (or bitwise) operation with an assignment in a single statement. They make code more concise, easier to read, and often more efficient.

The Fundamental Equivalence:

x += 3 is exactly equivalent to x = x + 3

Both statements do the same thing:

  1. Read the current value of x.
  2. Perform the operation (add 3).
  3. Assign the result back to x.

Why Use Augmented Assignments?

1.2 Complete List of Augmented Assignment Operators

Operator Shorthand Equivalent Description
+= x += 5 x = x + 5 Add and assign
-= x -= 5 x = x - 5 Subtract and assign
*= x *= 5 x = x * 5 Multiply and assign
/= x /= 5 x = x / 5 Divide and assign (returns float)
//= x //= 5 x = x // 5 Floor divide and assign
%= x %= 5 x = x % 5 Modulo and assign (remainder)
**= x **= 5 x = x ** 5 Exponentiate and assign
&= x &= 5 x = x & 5 Bitwise AND and assign
|= x |= 5 x = x | 5 Bitwise OR and assign
^= x ^= 5 x = x ^ 5 Bitwise XOR and assign
<<= x <<= 1 x = x << 1 Left shift and assign
>>= x >>= 1 x = x >> 1 Right shift and assign

Note: Bitwise operators are beyond the scope of this unit but are included for completeness.

1.3 How Augmented Assignment Works: Step-by-Step

Example with Numbers (Immutable):

x = 10 print(f"Before: x = {x}, id = {id(x)}") x += 3 # This is equivalent to: x = x + 3 # Step 1: Read x (10) # Step 2: Compute 10 + 3 = 13 (creates a new integer object) # Step 3: Assign 13 back to x (x now points to the new object) print(f"After: x = {x}, id = {id(x)}") # id will be different!

For immutable types (int, float, str, tuple), augmented assignment always creates a new object and rebinds the variable. This is functionally identical to x = x + value.

For mutable types (list, dict, set), augmented assignment can be different. It often modifies the object in-place rather than creating a new one.

Example with Lists (Mutable):

list1 = [1, 2, 3] print(f"Before: {list1}, id = {id(list1)}") list1 += [4, 5] # In-place extension print(f"After: {list1}, id = {id(list1)}") # SAME id! # Compare with regular addition (creates a new list): list2 = [1, 2, 3] print(f"Before regular: {list2}, id = {id(list2)}") list2 = list2 + [4, 5] # Creates a new list object print(f"After regular: {list2}, id = {id(list2)}") # DIFFERENT id!

Why This Difference Matters:

1.4 Practical Use Cases: The Accumulator Patterns

Augmented assignments are essential for building cumulative values.

1.4.1 Counter Pattern (Incrementing by 1):

counter = 0 counter += 1 # counter is now 1 counter += 1 # counter is now 2

1.4.2 Summation Accumulator (Running Total):

total = 0 for i in range(1, 6): # i = 1, 2, 3, 4, 5 total += i print(total) # 15 (1+2+3+4+5)

1.4.3 Product Accumulator (Factorial):

product = 1 for i in range(1, 6): # i = 1, 2, 3, 4, 5 product *= i print(product) # 120 (5!)

1.4.4 String Building:

message = "" for word in ["Hello", "World", "Python"]: message += word + " " print(message.strip()) # "Hello World Python"

Note: For large strings, using + repeatedly is inefficient. Use " ".join() instead for serious projects.

1.4.5 List Building (Appending via Augmented Assignment):

numbers = [] for i in range(5): numbers += [i] # Equivalent to numbers.append(i) print(numbers) # [0, 1, 2, 3, 4]

1.4.6 Cumulative Calculations with *= and **=:

balance = 1000 years = 5 for year in range(years): balance *= 1.05 # Apply 5% interest each year print(f"Year {year+1}: ${balance:.2f}")

1.5 Augmented Assignments with Different Data Types

Strings:

greeting = "Hello" greeting += " World" # greeting = greeting + " World" print(greeting) # "Hello World" repeated = "Ha" repeated *= 3 # repeated = repeated * 3 print(repeated) # "HaHaHa"

Lists:

fruits = ["apple"] fruits += ["banana", "cherry"] # In-place extension print(fruits) # ['apple', 'banana', 'cherry'] fruits *= 2 # Doubles the list print(fruits) # ['apple', 'banana', 'cherry', 'apple', 'banana', 'cherry']

Dictionaries:

# For dictionaries, you can't use += directly (unsupported) # But you can update with other dictionaries: inventory = {"apples": 10} inventory["apples"] += 5 # Update a value (works because we're updating a key) inventory["bananas"] = 0 # Then later... inventory["bananas"] += 3 # Works if key exists print(inventory) # {'apples': 15, 'bananas': 3}

Note: For dictionaries, you typically use dict.update() to merge.

1.6 Common Pitfalls and Mistakes

1.6.1 Uninitialized Variables:

# WRONG: This will raise a NameError total += 10 # NameError: name 'total' is not defined # CORRECT: Initialize first total = 0 total += 10 # Works!

1.6.2 Confusing += with + in Expressions:

# WRONG: Trying to use augmented assignment inside another expression result = (x += 5) * 2 # SyntaxError # CORRECT: Do it in two steps x += 5 result = x * 2

1.6.3 Type Mismatches:

x = 10 x += "5" # TypeError: unsupported operand type(s) for +=: 'int' and 'str' # Correct way: x += int("5") # x becomes 15

1.6.4 Integer Division Confusion:

x = 10 x //= 3 print(x) # 3 (integer division) print(type(x)) # <class 'int'> y = 10.0 y //= 3 print(y) # 3.0 (float division) print(type(y)) # <class 'float'>

1.6.5 The List += vs = list + Gotcha:

# Demonstration of aliasing danger a = [1, 2] b = a a += [3] # Modifies the SAME list print(b) # [1, 2, 3] ← b changed too! c = [1, 2] d = c c = c + [3] # Creates a NEW list print(d) # [1, 2] ← d is unchanged!

1.7 Performance Considerations

For Immutable Types (int, float, str):

For Mutable Types (list, dict, set):

Example Showing Performance Difference (Conceptual):

# Less efficient: Creates many intermediate strings text = "" for i in range(1000): text += str(i) # Creates a new string each time # More efficient: Joins all at once text = "".join(str(i) for i in range(1000)) # Single string creation

2. Code Examples (Annotated)

# --- Basic Augmented Assignments --- print("--- Basic Augmented Assignments ---") x = 5 print(f"x = {x}") x += 3 # x = x + 3 print(f"After += 3: {x}") x -= 2 # x = x - 2 print(f"After -= 2: {x}") x *= 2 # x = x * 2 print(f"After *= 2: {x}") x /= 4 # x = x / 4 print(f"After /= 4: {x}") x //= 2 # x = x // 2 print(f"After //= 2: {x}") x %= 3 # x = x % 3 print(f"After %= 3: {x}") x **= 3 # x = x ** 3 print(f"After **= 3: {x}") # --- String Operations --- print("\n--- Strings ---") greeting = "Hello" print(f"Greeting: {greeting}") greeting += " World" print(f"After += ' World': {greeting}") repeat = "Ha" repeat *= 3 print(f"After *= 3: {repeat}") # --- List Operations (In-Place Modification) --- print("\n--- Lists (In-Place) ---") numbers = [1, 2, 3] print(f"Before: {numbers}, id: {id(numbers)}") numbers += [4, 5] print(f"After += [4,5]: {numbers}, id: {id(numbers)}") numbers *= 2 print(f"After *= 2: {numbers}") # Compare with list + list (creates new object) print("\n--- List + List (New Object) ---") list1 = [1, 2, 3] print(f"Before: {list1}, id: {id(list1)}") list1 = list1 + [4, 5] print(f"After + [4,5]: {list1}, id: {id(list1)}") # Different id! # --- Practical Accumulators --- print("\n--- Accumulator Examples ---") # Summation total = 0 for i in range(1, 6): total += i print(f"Sum of 1-5: {total}") # 15 # Factorial factorial = 1 for i in range(1, 6): factorial *= i print(f"5!: {factorial}") # 120 # Counter counter = 0 for _ in range(5): # _ is a throwaway variable counter += 1 print(f"Counter: {counter}") # 5 # Interest calculation balance = 1000 for year in range(3): balance *= 1.05 print(f"Year {year+1}: ${balance:.2f}") # --- Advanced: Conditional Augmented Assignment --- print("\n--- Conditional ---") score = 85 if score >= 90: score += 5 # Bonus for high scores print(f"Score after bonus: {score}") # 85 (no bonus applied) # --- Dictionary Value Update --- print("\n--- Dictionaries ---") inventory = {"apples": 10, "bananas": 5} inventory["apples"] += 5 # Update existing key print(f"Inventory: {inventory}") # {'apples': 15, 'bananas': 5} # You can even do this with new keys (after initializing) inventory["oranges"] = 0 inventory["oranges"] += 3 print(f"After adding oranges: {inventory}") # {'apples': 15, 'bananas': 5, 'oranges': 3}

3. Quiz (Check Your Understanding)

Question 1: What is the value of x after x = 5; x += 3; x *= 2?
a) 16
b) 13
c) 11
d) 18

Answer a) `16` – `5+3=8`, then `8*2=16`.

Question 2: What is the equivalent long‑form for x //= 3?
a) x = x // 3
b) x // 3 = x
c) x = x / 3
d) x = // x 3

Answer a) `x = x // 3`

Question 3: Given text = "Hello", what is the result of text += " World"?
a) "HelloWorld"
b) "Hello World"
c) "WorldHello"
d) TypeError

Answer b) `"Hello World"`

Question 4: What happens with list1 = [1, 2]; list1 += [3, 4]?
a) list1 becomes [1, 2, 3, 4] (new object)
b) list1 becomes [1, 2, 3, 4] (same object, modified in‑place)
c) list1 becomes [1, 2]
d) TypeError

Answer b) – `+=` on a list modifies it in‑place.

Question 5: What is the output of x = 10; x /= 3; print(x)?
a) 3
b) 3.3333333333333335
c) 3.0
d) 4

Answer b) – division returns a float.

Question 6: What is the output of:

a = [1, 2] b = a a += [3] print(b)

a) [1, 2]
b) [1, 2, 3]
c) [3]
d) Error

Answer b) – `a += [3]` modifies the list in‑place, so `b` sees the change.

Question 7: What is the difference between x += y for an integer vs. a list?
a) No difference
b) For integers, it creates a new object; for lists, it modifies in‑place
c) For lists, it creates a new object; for integers, it modifies in‑place
d) Both create a new object

Answer b) – integers are immutable, lists are mutable.

Question 8: What is total after total = 1; for i in range(1, 4): total *= i?
a) 6
b) 3
c) 1
d) 0

Answer a) `6` – 1*1=1, 1*2=2, 2*3=6.

Question 9: Which is not a valid augmented assignment operator?
a) +=
b) -=
c) ++=
d) *=

Answer c) `++=` – not an operator in Python.

Question 10: What happens with x += 5 if x is not defined?
a) x is created with value 5
b) NameError
c) SyntaxError
d) TypeError

Answer b) `NameError`.

4. Exercises (In-Class / Lab Practice)

Exercise 1: Convert to Augmented Assignment
Convert the following standard assignments to augmented:
x = x + 5, y = y * 2, total = total / 3, count = count - 1, balance = balance * 1.1, text = text + "!", numbers = numbers + [10], value = value ** 2.

Sample Solution ```python x += 5 y *= 2 total /= 3 count -= 1 balance *= 1.1 text += "!" numbers += [10] value **= 2 ```

Exercise 2: Summation Calculator
Ask the user for how many numbers, then use a loop to accumulate the sum with += and print the sum and average.

Sample Solution ```python n = int(input("How many numbers? ")) total = 0 for i in range(n): num = float(input(f"Enter number {i+1}: ")) total += num print(f"Sum: {total}") print(f"Average: {total / n}") ```

Exercise 3: String Builder
Start with an empty string, ask for 5 words, append each with a space, and print the final sentence.

Sample Solution ```python result = "" for i in range(5): word = input(f"Enter word {i+1}: ") result += word + " " print(result.strip()) ```

Exercise 4: Interest Calculator

Write a program that:

  1. Asks the user for an initial investment amount (float).
  2. Asks for the annual interest rate (as a percentage).
  3. Asks for the number of years.
  4. Uses a loop and *= to calculate the balance each year.
  5. Prints the balance for each year formatted to 2 decimal places.
  6. Challenge: Also calculate and print the total interest earned.
Sample Answer
""" INTEREST CALCULATOR Calculates compound interest year by year using augmented assignment """ print("=" * 60) print("INTEREST CALCULATOR") print("=" * 60) # --- Get user input with error handling --- print("\nEnter your investment details:") try: principal = float(input(" Initial investment amount: $")) if principal < 0: print(" Warning: Investment amount should be positive.") principal = abs(principal) rate = float(input(" Annual interest rate (as %): ")) if rate < 0: print(" Warning: Interest rate should be positive.") rate = abs(rate) years = int(input(" Number of years: ")) if years < 0: print(" Warning: Years should be positive.") years = abs(years) except ValueError: print("\nInvalid input! Using default values: $1000, 5%, 10 years") principal = 1000.0 rate = 5.0 years = 10 print("\n" + "-" * 60) print("INVESTMENT DETAILS") print("-" * 60) print(f"Initial Investment: ${principal:,.2f}") print(f"Interest Rate: {rate}%") print(f"Number of Years: {years}") # --- Calculate balance each year using a loop and *= --- print("\n" + "-" * 60) print("YEAR-BY-YEAR GROWTH") print("-" * 60) # Initialize balance with the principal balance = principal # Print header print(f"{'Year':>6} | {'Balance':>12} | {'Interest Earned':>15}") print("-" * 60) total_interest = 0 # Loop through each year for year in range(1, years + 1): # Calculate interest for this year interest_this_year = balance * (rate / 100) # Use *= to add interest to the balance balance *= (1 + rate / 100) # balance = balance * (1 + rate/100) # Accumulate total interest total_interest += interest_this_year # Print year's balance print(f"{year:>6} | ${balance:>11,.2f} | ${interest_this_year:>14,.2f}") print("-" * 60) # --- Print final summary --- print("\n" + "-" * 60) print("FINAL SUMMARY") print("-" * 60) print(f"Initial Investment: ${principal:>11,.2f}") print(f"Final Balance: ${balance:>11,.2f}") print(f"Total Interest Earned: ${total_interest:>11,.2f}") # Calculate and print additional metrics total_growth = balance - principal growth_percentage = (total_growth / principal) * 100 print(f"Total Growth: ${total_growth:>11,.2f} ({growth_percentage:.1f}%)") # --- Challenge: Verify using formula --- print("\n" + "-" * 60) print("VERIFICATION (Using Compound Interest Formula)") print("-" * 60) # Formula: FV = P * (1 + r/100)^n future_value_formula = principal * (1 + rate / 100) ** years interest_formula = future_value_formula - principal print(f"Formula Future Value: ${future_value_formula:>11,.2f}") print(f"Formula Interest: ${interest_formula:>11,.2f}") print(f"Loop method matches? {'✅ Yes' if abs(balance - future_value_formula) < 0.01 else '❌ No'}") print("\n" + "=" * 60) print("KEY TAKEAWAYS") print("=" * 60) print(" • Use `balance *= (1 + rate/100)` to compound interest annually") print(" • Augmented assignment `*=` modifies the variable in-place") print(" • The loop method shows year-by-year growth") print(" • The formula `P * (1 + r/100)^n` gives the same result") print(" • Total interest = Final Balance - Principal") print("=" * 60)

Sample Output:

============================================================ INTEREST CALCULATOR ============================================================ Enter your investment details: Initial investment amount: $1000 Annual interest rate (as %): 5 Number of years: 10 ------------------------------------------------------------ INVESTMENT DETAILS ------------------------------------------------------------ Initial Investment: $1,000.00 Interest Rate: 5.0% Number of Years: 10 ------------------------------------------------------------ YEAR-BY-YEAR GROWTH ------------------------------------------------------------ Year | Balance | Interest Earned ------------------------------------------------------------ 1 | $1,050.00 | $50.00 2 | $1,102.50 | $52.50 3 | $1,157.63 | $55.13 4 | $1,215.51 | $57.88 5 | $1,276.28 | $60.78 6 | $1,340.10 | $63.81 7 | $1,407.10 | $67.01 8 | $1,477.46 | $70.35 9 | $1,551.33 | $73.87 10 | $1,628.89 | $77.56 ------------------------------------------------------------ ------------------------------------------------------------ FINAL SUMMARY ------------------------------------------------------------ Initial Investment: $1,000.00 Final Balance: $1,628.89 Total Interest Earned: $628.89 Total Growth: $628.89 (62.9%) ------------------------------------------------------------ VERIFICATION (Using Compound Interest Formula) ------------------------------------------------------------ Formula Future Value: $1,628.89 Formula Interest: $628.89 Loop method matches? ✅ Yes ============================================================ KEY TAKEAWAYS ============================================================ • Use `balance *= (1 + rate/100)` to compound interest annually • Augmented assignment `*=` modifies the variable in-place • The loop method shows year-by-year growth • The formula `P * (1 + r/100)^n` gives the same result • Total interest = Final Balance - Principal ============================================================

Explanation:

  1. balance *= (1 + rate / 100) – This is equivalent to balance = balance * (1 + rate / 100). It multiplies the balance by the growth factor each year.

  2. Year-by-year calculation – The loop shows how the balance grows each year, with interest earned on the new balance.

  3. Compound interest – Interest is calculated on the current balance (including previous interest).

  4. Verification – The loop result matches the compound interest formula.

Exercise 5: List Builder with Augmented Assignment

Write a program that:

  1. Creates an empty list squares = [].
  2. Uses a loop to iterate through numbers 1 to 10.
  3. For each number, calculates the square and appends it to the list using += (with the square as a single-element list).
  4. Prints the final list of squares.
  5. Advanced: Use *= 2 to double all elements in the list and print the doubled list.
Sample Answer
""" LIST BUILDER WITH AUGMENTED ASSIGNMENT Demonstrates using += and *= with lists """ print("=" * 60) print("LIST BUILDER WITH AUGMENTED ASSIGNMENT") print("=" * 60) # --- Step 1: Create empty list --- squares = [] print(f"Step 1 - squares initialized: {squares}") # --- Step 2: Build list using += --- print("\n" + "-" * 60) print("BUILDING SQUARES LIST (using +=)") print("-" * 60) for i in range(1, 11): # Calculate square square = i ** 2 # Append using += (adds a single-element list) squares += [square] # Show progress print(f" i={i:>2}, square={square:>3}, squares={squares}") print("\n" + "-" * 60) print("FINAL SQUARES LIST") print("-" * 60) print(f"Squares: {squares}") print(f"Length: {len(squares)}") print(f"ID: {id(squares)}") # --- Step 3: Demonstrate different ways to append --- print("\n" + "-" * 60) print("COMPARISON OF APPEND METHODS") print("-" * 60) # Method 1: Using += with single-element list print("\nMethod 1: squares += [value]") test_list1 = [] for i in range(1, 6): test_list1 += [i] print(f" Result: {test_list1}") # Method 2: Using append() method print("\nMethod 2: squares.append(value)") test_list2 = [] for i in range(1, 6): test_list2.append(i) print(f" Result: {test_list2}") # Method 3: Using extend() method print("\nMethod 3: squares.extend([value])") test_list3 = [] for i in range(1, 6): test_list3.extend([i]) print(f" Result: {test_list3}") print("\nAll three methods produce the same result!") # --- Step 4: Advanced - Double all elements using *= --- print("\n" + "-" * 60) print("ADVANCED: DOUBLING ALL ELEMENTS (using *=)") print("-" * 60) # Start from the original squares list doubled = squares[:] # Make a copy print(f"Before doubling: {doubled}") # Use *= to double all elements doubled *= 2 print(f"After doubling: {doubled}") print("\n" + "-" * 60) print("ANALYSIS") print("-" * 60) print(f"Original squares: {squares}") print(f"Doubled version: {doubled}") print(f"Original length: {len(squares)}") print(f"Doubled length: {len(doubled)}") # --- Step 5: More advanced list operations with *= --- print("\n" + "-" * 60) print("MORE LIST OPERATIONS WITH *=") print("-" * 60) # Example 1: Repeat a list base_list = [1, 2, 3] print(f"Base list: {base_list}") base_list *= 3 print(f"Repeated 3 times: {base_list}") # Example 2: Create pattern pattern = ["*"] pattern *= 5 print(f"Pattern: {pattern}") print(f"Pattern as string: {''.join(pattern)}") # Example 3: Mixed data types mixed = [1, "a", True] mixed *= 2 print(f"Mixed list doubled: {mixed}") print("\n" + "=" * 60) print("KEY TAKEAWAYS") print("=" * 60) print(" • `list += [value]` appends a single element (like `.append()`)") print(" • `list += [value1, value2]` extends the list with multiple elements") print(" • `list *= n` duplicates the entire list n times") print(" • `+=` and `*=` modify the list in-place (no new object created)") print(" • All these operations work on mutable sequences like lists") print("=" * 60)

Sample Output:

============================================================ LIST BUILDER WITH AUGMENTED ASSIGNMENT ============================================================ Step 1 - squares initialized: [] ------------------------------------------------------------ BUILDING SQUARES LIST (using +=) ------------------------------------------------------------ i= 1, square= 1, squares=[1] i= 2, square= 4, squares=[1, 4] i= 3, square= 9, squares=[1, 4, 9] i= 4, square= 16, squares=[1, 4, 9, 16] i= 5, square= 25, squares=[1, 4, 9, 16, 25] i= 6, square= 36, squares=[1, 4, 9, 16, 25, 36] i= 7, square= 49, squares=[1, 4, 9, 16, 25, 36, 49] i= 8, square= 64, squares=[1, 4, 9, 16, 25, 36, 49, 64] i= 9, square= 81, squares=[1, 4, 9, 16, 25, 36, 49, 64, 81] i=10, square=100, squares=[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] ------------------------------------------------------------ FINAL SQUARES LIST ------------------------------------------------------------ Squares: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] Length: 10 ID: 140734567890123 ------------------------------------------------------------ COMPARISON OF APPEND METHODS ------------------------------------------------------------ Method 1: squares += [value] Result: [1, 2, 3, 4, 5] Method 2: squares.append(value) Result: [1, 2, 3, 4, 5] Method 3: squares.extend([value]) Result: [1, 2, 3, 4, 5] All three methods produce the same result! ------------------------------------------------------------ ADVANCED: DOUBLING ALL ELEMENTS (using *=) ------------------------------------------------------------ Before doubling: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] After doubling: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100] ------------------------------------------------------------ ANALYSIS ------------------------------------------------------------ Original squares: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] Doubled version: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100] Original length: 10 Doubled length: 20 ------------------------------------------------------------ MORE LIST OPERATIONS WITH *= ------------------------------------------------------------ Base list: [1, 2, 3] Repeated 3 times: [1, 2, 3, 1, 2, 3, 1, 2, 3] Pattern: ['*', '*', '*', '*', '*'] Pattern as string: ***** Mixed list doubled: [1, 'a', True, 1, 'a', True] ============================================================ KEY TAKEAWAYS ============================================================ • `list += [value]` appends a single element (like `.append()`) • `list += [value1, value2]` extends the list with multiple elements • `list *= n` duplicates the entire list n times • `+=` and `*=` modify the list in-place (no new object created) • All these operations work on mutable sequences like lists ============================================================

Explanation:

  1. squares += [square] – Appends a single element to the list. This works because += on a list extends it by the elements of the right-hand list.

  2. Multiple ways to append:

    • += [value] – Concise and works like .extend([value])
    • .append(value) – The standard method
    • .extend([value]) – More explicit
  3. doubled *= 2 – Doubles the list by duplicating all elements. This is equivalent to doubled = doubled * 2.

  4. In-place modification – Both += and *= modify the list object in-place (no new list created).

Key Difference:

Exercise 6: Inventory Management

Write a program that:

  1. Creates a dictionary inventory = {"apples": 10, "bananas": 5, "oranges": 3}.
  2. Uses augmented assignments to:
  3. Prints the updated inventory.
  4. Bonus: Add a new item "grapes" with a quantity of 0, then use += to add 4 grapes.
Sample Answer
""" INVENTORY MANAGEMENT Demonstrates augmented assignment with dictionaries """ print("=" * 60) print("INVENTORY MANAGEMENT") print("=" * 60) # --- Step 1: Create the initial inventory --- inventory = {"apples": 10, "bananas": 5, "oranges": 3} print("\nInitial Inventory:") print_inventory(inventory) # --- Step 2: Update inventory using augmented assignments --- print("\n" + "-" * 60) print("UPDATING INVENTORY") print("-" * 60) # Add 2 apples (using +=) print("\n1. Adding 2 apples...") inventory["apples"] += 2 print(f" apples: {inventory['apples']}") # Remove 1 banana (using -=) print("\n2. Removing 1 banana...") inventory["bananas"] -= 1 print(f" bananas: {inventory['bananas']}") # Double the number of oranges (using *=) print("\n3. Doubling oranges...") inventory["oranges"] *= 2 print(f" oranges: {inventory['oranges']}") # --- Step 3: Print the updated inventory --- print("\n" + "-" * 60) print("UPDATED INVENTORY") print("-" * 60) print_inventory(inventory) # --- Step 4: Bonus - Add a new item "grapes" --- print("\n" + "-" * 60) print("BONUS: ADDING NEW ITEM") print("-" * 60) print("\n4. Adding new item 'grapes'...") inventory["grapes"] = 0 # Initialize with 0 print(f" After initialization: grapes = {inventory['grapes']}") # Use += to add 4 grapes inventory["grapes"] += 4 print(f" After adding 4 grapes: grapes = {inventory['grapes']}") # --- Step 5: Final inventory --- print("\n" + "=" * 60) print("FINAL INVENTORY") print("=" * 60) print_inventory(inventory) # --- Step 6: Additional operations --- print("\n" + "-" * 60) print("ADDITIONAL INVENTORY OPERATIONS") print("-" * 60) # Example of updating with other operations print("\nPerforming more updates:") inventory = {"apples": 10, "bananas": 5, "oranges": 3} # Reset # Multiple updates print(f"Starting inventory: {inventory}") inventory["apples"] += 3 inventory["bananas"] -= 2 inventory["oranges"] **= 2 # Square the oranges print(f"After operations: {inventory}") # Example of %= (modulo) inventory["apples"] %= 5 print(f"After apples %= 5: {inventory}") # Example of //= (floor division) inventory["bananas"] //= 2 print(f"After bananas //= 2: {inventory}") print("\n" + "=" * 60) print("KEY TAKEAWAYS") print("=" * 60) print(" • `inventory['key'] += value` updates a dictionary value in-place") print(" • All augmented assignment operators work with dictionary values") print(" • You must initialize a key before using `+=` (or other operators)") print(" • To add a new item: set it to 0 first, then use `+=`") print(" • Dictionary values are mutable if they are mutable objects") print("=" * 60)

Helper Function:

def print_inventory(inventory): """Helper function to print inventory nicely.""" print("-" * 40) print(f"{'Item':<12} {'Quantity':>10}") print("-" * 40) for item, quantity in inventory.items(): print(f"{item:<12} {quantity:>10}") print("-" * 40) total = sum(inventory.values()) print(f"{'TOTAL':<12} {total:>10}") print("-" * 40)

Sample Output:

============================================================ INVENTORY MANAGEMENT ============================================================ Initial Inventory: -------------------------------------------- Item Quantity -------------------------------------------- apples 10 bananas 5 oranges 3 -------------------------------------------- TOTAL 18 -------------------------------------------- ------------------------------------------------------------ UPDATING INVENTORY ------------------------------------------------------------ 1. Adding 2 apples... apples: 12 2. Removing 1 banana... bananas: 4 3. Doubling oranges... oranges: 6 ------------------------------------------------------------ UPDATED INVENTORY ------------------------------------------------------------ -------------------------------------------- Item Quantity -------------------------------------------- apples 12 bananas 4 oranges 6 -------------------------------------------- TOTAL 22 -------------------------------------------- ------------------------------------------------------------ BONUS: ADDING NEW ITEM ------------------------------------------------------------ 4. Adding new item 'grapes'... After initialization: grapes = 0 After adding 4 grapes: grapes = 4 ============================================================ FINAL INVENTORY ============================================================ -------------------------------------------- Item Quantity -------------------------------------------- apples 12 bananas 4 oranges 6 grapes 4 -------------------------------------------- TOTAL 26 -------------------------------------------- ------------------------------------------------------------ ADDITIONAL INVENTORY OPERATIONS ------------------------------------------------------------ Performing more updates: Starting inventory: {'apples': 10, 'bananas': 5, 'oranges': 3} After operations: {'apples': 13, 'bananas': 3, 'oranges': 9} After apples %= 5: {'apples': 3, 'bananas': 3, 'oranges': 9} After bananas //= 2: {'apples': 3, 'bananas': 1, 'oranges': 9} ============================================================ KEY TAKEAWAYS ============================================================ • `inventory['key'] += value` updates a dictionary value in-place • All augmented assignment operators work with dictionary values • You must initialize a key before using `+=` (or other operators) • To add a new item: set it to 0 first, then use `+=` • Dictionary values are mutable if they are mutable objects ============================================================

Explanation:

  1. Dictionary Value Updates:

    • inventory["apples"] += 2 – Equivalent to inventory["apples"] = inventory["apples"] + 2
    • The key must exist for += to work (otherwise you get a KeyError)
  2. Adding a New Item:

    • First initialize: inventory["grapes"] = 0
    • Then update: inventory["grapes"] += 4
  3. All Augmented Operators Work:

    • +=, -=, *=, /=, //=, %=, **=
    • All work on dictionary values as long as the key exists
  4. In-place Modification:

    • Dictionary values are modified in-place
    • No new dictionary is created

Common Pitfall:

# WRONG - This will cause a KeyError inventory = {"apples": 10} inventory["bananas"] += 5 # KeyError! 'bananas' doesn't exist # CORRECT - Initialize first inventory["bananas"] = 0 inventory["bananas"] += 5 # OR use a more advanced approach (beyond this unit) inventory["bananas"] = inventory.get("bananas", 0) + 5

Key Takeaways:

  1. Dictionary values can be updated using augmented assignments.
  2. Keys must exist before using +=, -=, etc. (unlike assigning a new key with =).
  3. Initialize new keys with 0 before using +=.
  4. All arithmetic augmented operators work with numeric dictionary values.
  5. In-place modification – dictionary values are updated directly.
## 5. Homework Questions (Deep Thinking)

Question 1 (Conceptual – Mutability and Augmented Assignments):
Explain the difference between list_a += list_b and list_a = list_a + list_b. When would you prefer one over the other?

Sample Answer `list_a += list_b` modifies the existing list in‑place (if it's mutable). `list_a = list_a + list_b` creates a new list object and rebinds `list_a` to it. Use `+=` when you want to update the original list and avoid creating a new object, especially if other variables reference that list. Use `+` when you need a new list but want to keep the original unchanged.

Question 2 (Code Analysis – Predict Output):
What is printed and why?

a = [1, 2, 3] b = a a = a + [4, 5] b += [6] print(a) print(b)
Sample Answer `a` initially points to `[1,2,3]`. `a = a + [4,5]` creates a new list `[1,2,3,4,5]` and rebinds `a`. `b` still points to the original list `[1,2,3]`. Then `b += [6]` modifies that original list in‑place, so `b` becomes `[1,2,3,6]`. `a` remains `[1,2,3,4,5]`. Output: `[1,2,3,4,5]` and `[1,2,3,6]`.

Question 3 (Real-World Application – Shopping Cart):

Write a complete program that simulates a shopping cart:

  1. Start with an empty list cart = [] and a total = 0.0.
  2. Use a loop that asks the user for an item name and price.
  3. If the user enters "done", stop the loop.
  4. Use += to add the item to the cart (as a tuple (item, price)).
  5. Use += to add the price to the total.
  6. After the loop, print the entire cart and the total bill.
  7. Bonus: Apply a 10% discount using *= if the total exceeds $100.
Sample Answer
""" SHOPPING CART SIMULATOR Demonstrates augmented assignment with lists and totals """ print("=" * 60) print("SHOPPING CART SIMULATOR") print("=" * 60) # --- Step 1: Initialize empty cart and total --- cart = [] total = 0.0 print("\nEnter items for your shopping cart.") print("Type 'done' when finished.\n") # --- Step 2-5: Loop to get items --- item_count = 0 while True: # Get item name item = input(f"Item #{item_count + 1} name (or 'done'): ").strip() # Check if user wants to stop if item.lower() == 'done': break # Get item price try: price = float(input(f" Price for '{item}': $")) if price < 0: print(" Price cannot be negative. Please try again.") continue except ValueError: print(" Invalid price. Please enter a number.") continue # --- Step 4: Add item to cart using += --- # cart += [(item, price)] # Adds a single tuple as a list element # Alternative: cart.append((item, price)) cart += [(item, price)] # --- Step 5: Add price to total using += --- total += price item_count += 1 print(f" Added: {item} (${price:.2f})") print(f" Cart total: ${total:.2f}\n") # --- Step 6: Display the cart and total --- print("\n" + "=" * 60) print("SHOPPING CART SUMMARY") print("=" * 60) if not cart: print("\nYour cart is empty.") else: print("\nItems in your cart:") print("-" * 50) print(f"{'Item':<30} {'Price':>10}") print("-" * 50) for item, price in cart: print(f"{item:<30} ${price:>9.2f}") print("-" * 50) # --- Step 7: Apply discount if total exceeds $100 --- original_total = total discount_applied = False if total > 100: print(f"Subtotal: ${total:>9.2f}") print("🎉 You qualify for a 10% discount!") # Apply discount using *= discount = total * 0.10 total *= 0.90 # total = total * 0.90 (10% discount) discount_applied = True print(f"Discount (10%): -${discount:>8.2f}") print("-" * 50) print(f"TOTAL: ${total:>9.2f}") if discount_applied: print(f"\nYou saved ${original_total - total:.2f} today!") print("\n" + "=" * 60) print("CART STATISTICS") print("=" * 60) # Additional statistics print(f"Total items: {len(cart)}") print(f"Original total: ${original_total:>9.2f}") print(f"Final total: ${total:>9.2f}") # Find most expensive item (without max()) if cart: most_expensive = cart[0] for item, price in cart: if price > most_expensive[1]: most_expensive = (item, price) print(f"Most expensive: {most_expensive[0]} (${most_expensive[1]:.2f})") print("\n" + "=" * 60) print("KEY TAKEAWAYS") print("=" * 60) print(" • `cart += [(item, price)]` adds a tuple to the list") print(" • `total += price` accumulates the running total") print(" • `total *= 0.90` applies a 10% discount") print(" • Augmented assignment works with lists (extend) and numbers") print(" • Always validate user input to prevent errors") print("=" * 60)

Sample Output (with discount):

============================================================ SHOPPING CART SIMULATOR ============================================================ Enter items for your shopping cart. Type 'done' when finished. Item #1 name (or 'done'): Laptop Price for 'Laptop': $999.99 Added: Laptop ($999.99) Cart total: $999.99 Item #2 name (or 'done'): Mouse Price for 'Mouse': $29.99 Added: Mouse ($29.99) Cart total: $1029.98 Item #3 name (or 'done'): done ============================================================ SHOPPING CART SUMMARY ============================================================ Items in your cart: -------------------------------------------------- Item Price -------------------------------------------------- Laptop $999.99 Mouse $29.99 -------------------------------------------------- Subtotal: $1029.98 🎉 You qualify for a 10% discount! Discount (10%): -$103.00 -------------------------------------------------- TOTAL: $926.98 You saved $103.00 today! ============================================================ CART STATISTICS ============================================================ Total items: 2 Original total: $1029.98 Final total: $926.98 Most expensive: Laptop ($999.99) ============================================================ KEY TAKEAWAYS ============================================================ • `cart += [(item, price)]` adds a tuple to the list • `total += price` accumulates the running total • `total *= 0.90` applies a 10% discount • Augmented assignment works with lists (extend) and numbers • Always validate user input to prevent errors ============================================================

Sample Output (no discount):

============================================================ SHOPPING CART SIMULATOR ============================================================ Enter items for your shopping cart. Type 'done' when finished. Item #1 name (or 'done'): Apple Price for 'Apple': $1.50 Added: Apple ($1.50) Cart total: $1.50 Item #2 name (or 'done'): Banana Price for 'Banana': $0.75 Added: Banana ($0.75) Cart total: $2.25 Item #3 name (or 'done'): done ============================================================ SHOPPING CART SUMMARY ============================================================ Items in your cart: -------------------------------------------------- Item Price -------------------------------------------------- Apple $1.50 Banana $0.75 -------------------------------------------------- TOTAL: $2.25 ============================================================ CART STATISTICS ============================================================ Total items: 2 Original total: $2.25 Final total: $2.25 Most expensive: Apple ($1.50) ============================================================ KEY TAKEAWAYS ============================================================ • `cart += [(item, price)]` adds a tuple to the list • `total += price` accumulates the running total • `total *= 0.90` applies a 10% discount • Augmented assignment works with lists (extend) and numbers • Always validate user input to prevent errors ============================================================

Explanation:

  1. cart += [(item, price)] – This extends the list by adding a single tuple. It's equivalent to cart.append((item, price)).

  2. total += price – Adds the price to the running total.

  3. total *= 0.90 – Applies a 10% discount (multiplies by 0.90). This is only applied if the condition total > 100 is true.

  4. Data Structure – Each item is stored as a tuple (name, price) inside the list.

  5. Loop Controlwhile True with break when "done" is entered.

Question 4 (Performance Consideration – String Building):

What is the issue with using += to build a long string in a loop (e.g., for i in range(10000): result += str(i))? Research and explain why this is inefficient. What is the recommended alternative?

Sample Answer
""" STRING BUILDING PERFORMANCE COMPARISON Demonstrates why using += in a loop is inefficient for strings """ import time print("=" * 60) print("STRING BUILDING PERFORMANCE COMPARISON") print("=" * 60) # --- The Problem: Using += in a loop --- print("\n" + "-" * 60) print("METHOD 1: Using += (Inefficient)") print("-" * 60) print("\nWhat happens when you use `result += str(i)` in a loop?") print("-" * 40) # Explanation with a small example result = "" for i in range(5): result += str(i) print(f" Step {i+1}: result = '{result}' (creates a new string)") print("\nAt each step, a NEW string is created and the old one is discarded!") print("\n" + "-" * 60) print("THE PROBLEM EXPLAINED") print("-" * 60) print(""" Strings in Python are IMMUTABLE (cannot be changed). When you do `result += str(i)`, Python: 1. Reads the current value of 'result' 2. Creates a NEW string with the concatenated result 3. Assigns 'result' to point to the new string 4. The old string is garbage-collected This creates many intermediate strings. For n items: • 1st iteration: creates 1 string • 2nd iteration: creates 1 string • ... • nth iteration: creates 1 string Total: n strings are created, but only the final one is needed! Time complexity: O(n²) because each concatenation copies the entire string. """) # --- Performance comparison --- print("\n" + "-" * 60) print("PERFORMANCE COMPARISON") print("-" * 60) print("\nTesting with 10,000 iterations:") # Method 1: Using += (inefficient) start_time = time.time() result_append = "" for i in range(10000): result_append += str(i) time_append = time.time() - start_time print(f"\nMethod 1 (+=): {time_append:.6f} seconds") # Method 2: Using join() (efficient) start_time = time.time() parts = [] for i in range(10000): parts.append(str(i)) result_join = "".join(parts) time_join = time.time() - start_time print(f"Method 2 (join()): {time_join:.6f} seconds") # Method 3: Using join() with generator (most efficient) start_time = time.time() result_generator = "".join(str(i) for i in range(10000)) time_generator = time.time() - start_time print(f"Method 3 (generator): {time_generator:.6f} seconds") if time_append > 0: speedup = time_append / time_join print(f"\n✅ join() is {speedup:.1f}x faster than using +=!") # --- Demonstration with a larger test --- print("\n" + "-" * 60) print("TESTING WITH DIFFERENT SIZES") print("-" * 60) def test_string_building(size, method='join'): """Test string building with different methods.""" if method == 'append': result = "" for i in range(size): result += str(i) return result elif method == 'join': return "".join(str(i) for i in range(size)) elif method == 'list_join': parts = [] for i in range(size): parts.append(str(i)) return "".join(parts) # Test with different sizes sizes = [100, 1000, 5000, 10000] print(f"{'Size':>8} | {'+= Time':>12} | {'join() Time':>12} | {'Speedup':>10}") print("-" * 55) for size in sizes: # Time the += method start = time.time() test_string_building(size, 'append') time_append = time.time() - start # Time the join() method start = time.time() test_string_building(size, 'join') time_join = time.time() - start speedup = time_append / time_join if time_join > 0 else 0 print(f"{size:>8} | {time_append:>11.6f}s | {time_join:>11.6f}s | {speedup:>9.1f}x") print("\n" + "-" * 60) print("WHY THIS HAPPENS") print("-" * 60) print(""" The += method has O(n²) time complexity because: • Each concatenation copies the entire existing string • The cost grows with the string length • For n = 10,000, this means 100 million operations! The join() method has O(n) time complexity because: • It first collects all strings in a list • It pre-calculates the total length • It allocates memory ONCE for the final string • It copies each string exactly ONCE This makes join() MUCH faster for large string concatenations. """) print("\n" + "=" * 60) print("THE RECOMMENDED ALTERNATIVE") print("=" * 60) print(""" ✅ USE `''.join()` for concatenating multiple strings! The recommended pattern is: ```python parts = [] for i in range(10000): parts.append(str(i)) result = ''.join(parts)

Or more concisely:

result = ''.join(str(i) for i in range(10000))

This is the standard Pythonic way to build strings efficiently. """)

print("\n" + "-" 60) print("EXCEPTIONS") print("-" 60)

print(""" There are a few cases where using += is acceptable:

  1. Very small strings (a few concatenations)
  2. One-off string building (not in a loop)
  3. When readability is more important than performance

Example where += is fine:

greeting = "Hello" greeting += " World" greeting += "!"

But for loops with many iterations, always use join()! """)

print("\n" + "=" 60) print("KEY TAKEAWAYS") print("=" 60) print(" • Strings are immutable – each += creates a new string") print(" • += in a loop has O(n²) time complexity") print(" • Use ''.join(list) for efficient string concatenation") print(" • join() allocates memory once and copies each string once") print(" • For small strings or few concatenations, += is acceptable") print("=" * 60)

**Sample Output:**

============================================================ STRING BUILDING PERFORMANCE COMPARISON


METHOD 1: Using += (Inefficient)

What happens when you use result += str(i) in a loop?

Step 1: result = '0' (creates a new string) Step 2: result = '01' (creates a new string) Step 3: result = '012' (creates a new string) Step 4: result = '0123' (creates a new string) Step 5: result = '01234' (creates a new string)

At each step, a NEW string is created and the old one is discarded!


THE PROBLEM EXPLAINED

Strings in Python are IMMUTABLE (cannot be changed).

When you do result += str(i), Python:

  1. Reads the current value of 'result'
  2. Creates a NEW string with the concatenated result
  3. Assigns 'result' to point to the new string
  4. The old string is garbage-collected

This creates many intermediate strings. For n items: • 1st iteration: creates 1 string • 2nd iteration: creates 1 string • ... • nth iteration: creates 1 string

Total: n strings are created, but only the final one is needed!

Time complexity: O(n²) because each concatenation copies the entire string.


PERFORMANCE COMPARISON

Testing with 10,000 iterations:

Method 1 (+=): 0.023456 seconds Method 2 (join()): 0.001234 seconds Method 3 (generator): 0.001123 seconds

✅ join() is 19.0x faster than using +=!


TESTING WITH DIFFERENT SIZES

Size |     += Time |  join() Time |   Speedup

 100 |   0.000234s |   0.000045s |       5.2x
1000 |   0.002345s |   0.000123s |      19.1x
5000 |   0.012345s |   0.000456s |      27.1x

10000 | 0.045678s | 0.000789s | 57.9x


WHY THIS HAPPENS

The += method has O(n²) time complexity because: • Each concatenation copies the entire existing string • The cost grows with the string length • For n = 10,000, this means 100 million operations!

The join() method has O(n) time complexity because: • It first collects all strings in a list • It pre-calculates the total length • It allocates memory ONCE for the final string • It copies each string exactly ONCE

This makes join() MUCH faster for large string concatenations.

============================================================ THE RECOMMENDED ALTERNATIVE

✅ USE ''.join() for concatenating multiple strings!

The recommended pattern is:

parts = [] for i in range(10000): parts.append(str(i)) result = ''.join(parts)

Or more concisely:

result = ''.join(str(i) for i in range(10000))

This is the standard Pythonic way to build strings efficiently.

============================================================ KEY TAKEAWAYS

• Strings are immutable – each += creates a new string • += in a loop has O(n²) time complexity • Use ''.join(list) for efficient string concatenation • join() allocates memory once and copies each string once • For small strings or few concatenations, += is acceptable

**Explanation:** **The Problem:** 1. **Strings are immutable** – They cannot be modified in-place. 2. **`+=` creates new strings** – Each concatenation creates a new string object. 3. **O(n²) complexity** – Each concatenation copies the entire growing string. 4. **Memory waste** – Many intermediate strings are created and discarded. **The Solution:** 1. **`''.join(list)`** – The standard Python way to build strings. 2. **O(n) complexity** – Allocates memory once and copies each string once. 3. **Memory efficient** – No intermediate strings created. 4. **Faster** – Significantly faster for large operations. **When to Use Each:** - **Small strings** – `+=` is acceptable (e.g., building a short message). - **Large strings or loops** – Always use `join()`. - **One-off concatenation** – `+=` is fine. - **Many concatenations** – Use `join()` for performance. </details> **Question 5 (Challenge – Stats Calculator):** Write a program that: 1. Creates a list `grades = [85, 92, 78, 90, 88, 76, 95]`. 2. Calculates and prints: - The sum of all grades (use a loop with `+=`). - The average (use `/=` or `/`). - The highest grade (use a loop and a conditional, no `max()` function). - The lowest grade (use a loop and a conditional, no `min()` function). 3. **Advanced:** Calculate the standard deviation using the formula `sqrt(sum((x - mean)**2) / n)`. You'll need to use `**=` and `+=` in loops. <details><summary>Sample Answer</summary> ```python """ STATS CALCULATOR Calculates statistics using loops and augmented assignment """ import math print("=" * 60) print("STATS CALCULATOR") print("=" * 60) # --- Step 1: Create the grades list --- grades = [85, 92, 78, 90, 88, 76, 95] print(f"\nGrades: {grades}") print(f"Number of grades: {len(grades)}") print("\n" + "-" * 60) print("BASIC STATISTICS") print("-" * 60) # --- Step 2a: Calculate sum using loop with += --- sum_grades = 0 for grade in grades: sum_grades += grade print(f"Sum: {sum_grades}") # --- Step 2b: Calculate average using /= --- avg = sum_grades / len(grades) print(f"Average: {avg:.2f}") # --- Step 2c: Find highest grade (no max()) --- highest = grades[0] # Start with first element for grade in grades: if grade > highest: highest = grade print(f"Highest: {highest}") # --- Step 2d: Find lowest grade (no min()) --- lowest = grades[0] # Start with first element for grade in grades: if grade < lowest: lowest = grade print(f"Lowest: {lowest}") print("\n" + "-" * 60) print("ADDITIONAL STATISTICS") print("-" * 60) # --- Additional statistics using built-in functions --- print(f"\nUsing built-in functions (for verification):") print(f" sum(grades): {sum(grades)}") print(f" max(grades): {max(grades)}") print(f" min(grades): {min(grades)}") print(f" len(grades): {len(grades)}") print(f" Average: {sum(grades) / len(grades):.2f}") # --- Step 3: Advanced - Calculate standard deviation --- print("\n" + "-" * 60) print("ADVANCED: STANDARD DEVIATION") print("-" * 60) # Formula: σ = sqrt(Σ(x - mean)² / n) # Step 1: Calculate sum of squared differences using += and **= sum_squared_diff = 0 for grade in grades: diff = grade - avg diff_squared = diff ** 2 # Using ** operator sum_squared_diff += diff_squared # Or use **= with a variable # diff = grade - avg # diff **= 2 # sum_squared_diff += diff print(f"\nStep-by-step calculation:") print(f" Mean: {avg:.2f}") print(f" Sum of squared differences: {sum_squared_diff:.2f}") # Step 2: Calculate variance variance = sum_squared_diff / len(grades) print(f" Variance: {variance:.2f}") # Step 3: Calculate standard deviation (square root) std_dev = math.sqrt(variance) print(f" Standard Deviation: {std_dev:.2f}") # --- Alternative: Using a single loop with **= --- print("\n" + "-" * 60) print("ALTERNATIVE CALCULATION") print("-" * 60) # Using **= within the loop sum_sq_diff = 0 for grade in grades: diff = grade - avg diff **= 2 # Square the difference sum_sq_diff += diff std_dev_alt = math.sqrt(sum_sq_diff / len(grades)) print(f"Using **= in loop:") print(f" Standard Deviation: {std_dev_alt:.2f}") print(f" Matches previous result? {'✅ Yes' if abs(std_dev - std_dev_alt) < 0.001 else '❌ No'}") # --- More advanced statistics --- print("\n" + "-" * 60) print("ADVANCED STATISTICS") print("-" * 60) # Sort grades (using sorted) sorted_grades = sorted(grades) print(f"Sorted grades: {sorted_grades}") # Median n = len(grades) if n % 2 == 1: median = sorted_grades[n // 2] else: median = (sorted_grades[n // 2 - 1] + sorted_grades[n // 2]) / 2 print(f"Median: {median}") # Range range_val = highest - lowest print(f"Range: {range_val}") # Grade distribution print("\nGrade Distribution:") def get_letter(score): if score >= 90: return 'A' elif score >= 80: return 'B' elif score >= 70: return 'C' elif score >= 60: return 'D' else: return 'F' # Count letter grades letter_counts = {} for grade in grades: letter = get_letter(grade) letter_counts[letter] = letter_counts.get(letter, 0) + 1 for letter in ['A', 'B', 'C', 'D', 'F']: count = letter_counts.get(letter, 0) if count > 0: print(f" {letter}: {count} grade(s)") # --- Step-by-step standard deviation calculation with explanations --- print("\n" + "-" * 60) print("STANDARD DEVIATION STEP-BY-STEP") print("-" * 60) print("\nDetailed calculation of standard deviation:") print(f"Grades: {grades}") print(f"Mean: {avg:.2f}\n") print("Step 1: Calculate squared differences (x - mean)²") print(f"{'Grade':>8} | {'x - mean':>12} | {'(x - mean)²':>14}") print("-" * 45) sum_sq = 0 for grade in grades: diff = grade - avg diff_sq = diff ** 2 sum_sq += diff_sq print(f"{grade:>8} | {diff:>11.2f} | {diff_sq:>13.2f}") print("-" * 45) print(f"{'TOTAL':>8} | {'':>12} | {sum_sq:>14.2f}") print(f"\nStep 2: Variance = sum_sq / n = {sum_sq} / {len(grades)} = {sum_sq / len(grades):.2f}") print(f"Step 3: Standard Deviation = sqrt(Variance) = sqrt({sum_sq / len(grades):.2f}) = {math.sqrt(sum_sq / len(grades)):.2f}") print("\n" + "=" * 60) print("KEY TAKEAWAYS") print("=" * 60) print(" • Use `sum_var += value` to accumulate totals in loops") print(" • Use `value **= 2` to square a value in-place") print(" • Use `value /= n` to divide and assign") print(" • Manual loops can replace built-in functions like sum(), max(), min()") print(" • Augmented assignment makes code more concise") print(" • Standard deviation measures the spread of data around the mean") print("=" * 60)

Sample Output:

============================================================ STATS CALCULATOR ============================================================ Grades: [85, 92, 78, 90, 88, 76, 95] Number of grades: 7 ------------------------------------------------------------ BASIC STATISTICS ------------------------------------------------------------ Sum: 604 Average: 86.29 Highest: 95 Lowest: 76 ------------------------------------------------------------ ADDITIONAL STATISTICS ------------------------------------------------------------ Using built-in functions (for verification): sum(grades): 604 max(grades): 95 min(grades): 76 len(grades): 7 Average: 86.29 ------------------------------------------------------------ ADVANCED: STANDARD DEVIATION ------------------------------------------------------------ Step-by-step calculation: Mean: 86.29 Sum of squared differences: 259.43 Variance: 37.06 Standard Deviation: 6.09 ------------------------------------------------------------ ALTERNATIVE CALCULATION ------------------------------------------------------------ Using **= in loop: Standard Deviation: 6.09 Matches previous result? ✅ Yes ------------------------------------------------------------ ADVANCED STATISTICS ------------------------------------------------------------ Sorted grades: [76, 78, 85, 88, 90, 92, 95] Median: 88 Range: 19 Grade Distribution: A: 2 grade(s) B: 3 grade(s) C: 1 grade(s) D: 1 grade(s) ------------------------------------------------------------ STANDARD DEVIATION STEP-BY-STEP ------------------------------------------------------------ Detailed calculation of standard deviation: Grades: [85, 92, 78, 90, 88, 76, 95] Mean: 86.29 Step 1: Calculate squared differences (x - mean)² Grade | x - mean | (x - mean)² --------------------------------------------- 85 | -1.29 | 1.65 92 | 5.71 | 32.65 78 | -8.29 | 68.65 90 | 3.71 | 13.79 88 | 1.71 | 2.94 76 | -10.29 | 105.79 95 | 8.71 | 75.94 --------------------------------------------- TOTAL | | 259.43 Step 2: Variance = sum_sq / n = 259.43 / 7 = 37.06 Step 3: Standard Deviation = sqrt(Variance) = sqrt(37.06) = 6.09 ============================================================ KEY TAKEAWAYS ============================================================ • Use `sum_var += value` to accumulate totals in loops • Use `value **= 2` to square a value in-place • Use `value /= n` to divide and assign • Manual loops can replace built-in functions like sum(), max(), min() • Augmented assignment makes code more concise • Standard deviation measures the spread of data around the mean ============================================================

Explanation:

Basic Statistics (Manual Calculations):

  1. Sum using +=sum_grades += grade accumulates the total.
  2. Averageavg = sum_grades / len(grades).
  3. Highest using conditional – Compare each grade to the current highest.
  4. Lowest using conditional – Compare each grade to the current lowest.

Advanced Statistics:

  1. Standard Deviation Formulaσ = sqrt(Σ(x - μ)² / n)
  2. Using **=diff **= 2 squares the difference in-place.
  3. Using +=sum_sq_diff += diff_sq accumulates squared differences.
  4. Using math.sqrt() – Calculate the square root.

Step-by-Step Standard Deviation:

  1. Calculate the mean (average).
  2. For each value, calculate (value - mean)².
  3. Sum all squared differences.
  4. Divide by the number of values (variance).
  5. Take the square root (standard deviation).

Why Standard Deviation Matters:

## 6. Summary Checklist (For Student Self-Review)

7. Additional Challenge: The Accumulator Puzzle

Learning Objective

Write a program that calculates the sum of squares and the sum of cubes of the first 10 positive integers using augmented assignments and loops.

Instructions: Write a program that:

  1. Initializes sum_squares = 0 and sum_cubes = 0.
  2. Uses a loop from 1 to 10.
  3. For each number i, uses += to add i**2 to sum_squares and i**3 to sum_cubes.
  4. Prints both results.
  5. Extra Challenge: Calculate and print the square root of the sum of squares using **= or ** with 0.5 as exponent.

Sample Output:

Sum of squares (1^2 to 10^2): 385 Sum of cubes (1^3 to 10^3): 3025 Square root of sum of squares: 19.621416870348583

Previous | Tutorial index | Next