Previous | Tutorial index | Next

Tutorial 5: Assignment Statements

Corresponding Objective

Write an assignment statement to assign values to variables.

1. Introduction

1.1 The Purpose of Assignment: Binding Names to Values

In Python, an assignment statement creates a binding between a name (variable) and an object in memory. Think of it like putting a label on a box:

Key Insight: Assignment does not copy the value; it simply creates a reference from the variable name to the object. This is why Python is often described as having "variables as references" rather than "variables as containers."

Real-World Analogy:

1.2 Basic Syntax: The Simple Assignment Statement

The fundamental form is:

variable_name = expression

Examples:

# Literal assignment age = 25 # Variable assignment (copying reference) my_age = age # Arithmetic expression total = price * quantity # Function call assignment name_length = len("Python") # Complex expression result = (price * quantity) - discount + tax

Multiple Assignment in One Statement: You can assign the same value to multiple variables:

x = y = z = 0

This is called chained assignment. All three variables reference the same object 0. For immutable objects like 0, this is safe.

1.3 Execution Order: The Right Side is Evaluated First

This is a critical concept that causes many bugs for beginners.

The Rule: Python always:

  1. Evaluates the entire right-hand side expression completely.
  2. Assigns the resulting value to the left-hand side.

The Famous n = n + 1 Example:

n = 5 # n points to 5 n = n + 1 # Step 1: Calculate n + 1 (5 + 1 = 6) # Step 2: Assign 6 to n (n now points to 6) print(n) # 6

Why This Works:

Memory Diagram of n = n + 1:

Before: n → [5] Step 1: Read n (5) → Calculate 5+1 = 6 → Create new object [6] Step 2: Rebind n → [6] After: n → [6] (old [5] has no references)

Another Example to Solidify Understanding:

a = 10 b = a # b now points to the same object as a (10) a = a + 5 # Calculate a+5 (15), bind a to new object 15 print(a) # 15 print(b) # 10 (b still points to the old 10 object!)

This demonstrates that b was not affected when a was reassigned because integers are immutable.

1.4 Dynamic Typing: Variables Are Not Fixed to a Type

Python is dynamically typed, meaning:

Example:

x = 10 # x is now an int print(type(x)) # <class 'int'> x = "Hello" # x is now a str (completely legal) print(type(x)) # <class 'str'> x = [1, 2, 3] # x is now a list print(type(x)) # <class 'list'>

Why This Matters:

Type Checking Safely:

value = input("Enter a number: ") # value is always a string if value.isdigit(): # Check if it's all digits number = int(value) print(f"Doubled: {number * 2}") else: print("That's not a valid number.")

1.5 Multiple Assignments (Tuple Unpacking)

Python allows you to assign multiple variables in a single line. This is called tuple unpacking.

Basic Form:

x, y = 3, 4 # Equivalent to: x = 3; y = 4

How It Works Internally:

Unpacking Lists and Strings:

# Unpacking a list a, b, c = [1, 2, 3] # a=1, b=2, c=3 # Unpacking a string (each character) first, second, third = "ABC" # first='A', second='B', third='C' # Unpacking with extra values using * (star) operator (Python 3+) first, *rest = [1, 2, 3, 4] # first=1, rest=[2, 3, 4] *first, last = [1, 2, 3] # first=[1, 2], last=3

Important: Number of Variables Must Match the Number of Values

x, y = 3, 4, 5 # ValueError: too many values to unpack x, y = 3 # ValueError: not enough values to unpack

Unpacking Dictionaries (Unpacks Keys):

person = {"name": "Alice", "age": 25} key1, key2 = person # key1='name', key2='age' print(key1, key2) # name age

1.6 Swapping Variables: The Pythonic Way

In many programming languages, swapping two variables requires a temporary variable:

# Traditional approach (works in Python too) temp = a a = b b = temp

Python's Elegant Approach:

a, b = b, a

How This Works:

  1. The right side b, a creates a tuple (b, a).
  2. The left side a, b unpacks this tuple.
  3. So a gets the old value of b, and b gets the old value of a.
  4. No temporary variable needed!

Example:

a = 5 b = 10 print(f"Before: a={a}, b={b}") # Before: a=5, b=10 a, b = b, a print(f"After: a={a}, b={b}") # After: a=10, b=5

Advanced Swap with More Variables:

x, y, z = 1, 2, 3 x, y, z = z, x, y # Rotates values print(x, y, z) # 3, 1, 2

1.7 Special Cases: Assignment with Mutable Objects

When you assign a mutable object (like a list or dictionary) to two variables, both variables reference the same object. Changing one affects the other.

Aliasing Example:

list1 = [1, 2, 3] list2 = list1 # list2 points to the SAME list as list1 list2.append(4) # Modifies the shared list print(list1) # [1, 2, 3, 4] ← list1 changed too! print(list2) # [1, 2, 3, 4]

How to Create an Independent Copy:

Example of Independent Copy:

list1 = [1, 2, 3] list2 = list1[:] # Creates a new list object list2.append(4) print(list1) # [1, 2, 3] ← unchanged print(list2) # [1, 2, 3, 4]

1.8 The = Operator vs. == Operator (Crucial Distinction)

New programmers often confuse assignment (=) with equality comparison (==).

Operator Purpose Example Result
= Assignment (binds a value to a variable) x = 10 Puts 10 into x
== Equality comparison (asks if two values are equal) x == 10 True or False

Common Mistake:

if x = 10: # SyntaxError! Use == for comparison print("x is 10")

Correct Version:

if x == 10: # Correct: checks equality print("x is 10")

1.9 Assignment in Conditional Contexts (The Walrus Operator – Advanced Preview)

Python 3.8 introduced the walrus operator := (assignment expression), which allows assignment within an expression. This is an advanced topic but worth a brief mention:

# Without walrus operator data = input("Enter: ") if len(data) > 0: print(f"You entered: {data}") # With walrus operator (combines assignment and condition) if (data := input("Enter: ")) and len(data) > 0: print(f"You entered: {data}")

Note: This is optional and not required for this unit. Students can ignore it for now.

2. Code Examples (Annotated)

# --- Basic Assignment --- print("--- Basic Assignment ---") age = 25 name = "Alice" price = 9.99 quantity = 3 total = price * quantity print(f"{name} bought {quantity} items for ${total:.2f}") # --- Execution Order (Right Side First) --- print("\n--- Execution Order ---") n = 5 print(f"Before: n = {n}") # 5 n = n + 1 print(f"After: n = {n}") # 6 # Demonstrating that right side is evaluated using current values a = 10 b = a # b gets the current value of a (10) a = a + 5 print(f"a = {a}, b = {b}") # a=15, b=10 (b unchanged) # --- Dynamic Typing --- print("\n--- Dynamic Typing ---") x = 10 print(f"x = {x}, type = {type(x)}") x = "Hello" print(f"x = {x}, type = {type(x)}") x = [1, 2, 3] print(f"x = {x}, type = {type(x)}") # --- Multiple Assignment --- print("\n--- Multiple Assignment ---") x, y = 3, 4 print(f"x = {x}, y = {y}") # 3, 4 # Swapping print("\n--- Swapping ---") a, b = 5, 10 print(f"Before: a={a}, b={b}") a, b = b, a print(f"After: a={a}, b={b}") # Chained assignment x = y = z = 0 print(f"x={x}, y={y}, z={z}") # --- Mutability and Aliasing --- print("\n--- Aliasing ---") list1 = [1, 2, 3] list2 = list1 # list2 points to the same object list2.append(4) print(f"list1: {list1}") # [1, 2, 3, 4] print(f"list2: {list2}") # [1, 2, 3, 4] # Creating an independent copy list3 = list1[:] # Slicing creates a new list list3.append(5) print(f"list1 (after copy change): {list1}") # [1, 2, 3, 4] (unchanged) print(f"list3: {list3}") # [1, 2, 3, 4, 5] # --- Unpacking Various Types --- print("\n--- Unpacking ---") # Tuple unpacking point = (10, 20) x, y = point print(f"Point: x={x}, y={y}") # List unpacking colors = ["red", "green", "blue"] r, g, b = colors print(f"RGB: {r}, {g}, {b}") # String unpacking first, second, third = "ABC" print(f"Chars: {first}, {second}, {third}") # Extended unpacking (star operator) numbers = [1, 2, 3, 4, 5] first, *middle, last = numbers print(f"first={first}, middle={middle}, last={last}") # --- Common Mistake: Using = instead of == --- print("\n--- Comparison vs Assignment ---") value = 10 # if value = 10: # SyntaxError! # print("This won't work") if value == 10: # Correct print("Value is 10")

3. Quiz (Check Your Understanding)

Question 1: What is the output of the following code?

x = 10 y = x x = 20 print(y)

a) 10 b) 20 c) None d) Error

Answer a) `10` – `y` was assigned the value of `x` at that time (10), and later `x` changed but `y` still points to the old integer object.

Question 2: What is the value of x after x = 5; x = x * 2 + 1? a) 5 b) 11 c) 12 d) 6

Answer b) `11` – `x*2+1` = `5*2+1` = `11`.

Question 3: What is the output of a, b = b, a if a = 3 and b = 7? a) a=7, b=3 b) a=3, b=7 c) a=7, b=7 d) a=3, b=3

Answer a) `a=7, b=3` – swap.

Question 4: Which of the following is a valid assignment statement? a) 5 = x b) x + y = 10 c) x = 10 d) if = 5

Answer c) `x = 10`

Question 5: What is the type of x after x = "123"? a) int b) str c) float d) bool

Answer b) `str`

Question 6: What happens when you execute x, y = 1, 2, 3?
a) x=1, y=2 (3 ignored)
b) x=1, y=2, x=3
c) ValueError: too many values to unpack
d) SyntaxError

Answer c) `ValueError: too many values to unpack`

Question 7: Given list1 = [1, 2]; list2 = list1; list2.append(3); print(list1), what is the output?
a) [1, 2]
b) [1, 2, 3]
c) [1, 3]
d) Error

Answer b) `[1, 2, 3]` – because `list2` references the same list object.

Question 8: What is the difference between x = 10 and x == 10?
a) No difference; both assign 10 to x
b) First assigns 10 to x; second compares x to 10
c) First compares x to 10; second assigns 10 to x
d) Both are invalid

Answer b) First is assignment, second is equality comparison.

Question 9: Which correctly creates an independent copy of my_list = [1, 2, 3]?
a) copy = my_list
b) copy = my_list[:]
c) copy = my_list.copy()
d) Both b and c

Answer d) Both b and c.

Question 10: What is the output of?

a = 10 b = 20 a, b = b, a + 5 print(a, b)

a) 20 15
b) 20 10
c) 10 20
d) 15 20

Answer a) `20 15` – right side evaluates `(b, a+5)` = `(20, 15)`, then assigns to `a` and `b`.

4. Exercises (In-Class / Lab Practice)

cise 1: Assignment Tracing**
Trace the following code manually (without running). Write down the value of each variable after each step.

x = 5 y = 10 z = x + y x = z + 5 y = x - y z = y - x print(x, y, z)
Sample Solution After step 1: x=5, y=10, z undefined After step 2: z=15 After step 3: x=20 After step 4: y=10? Wait: x=20, y=10, y becomes 20-10 = 10, so y=10. After step 5: z = y - x = 10 - 20 = -10. Final: x=20, y=10, z=-10.

Exercise 2: Swapping Challenge
Write a Python script that takes two numbers from the user and swaps them using the Pythonic method, printing before and after.

Sample Solution ```python num1 = input("Enter first number: ") num2 = input("Enter second number: ") print(f"Before: num1={num1}, num2={num2}") num1, num2 = num2, num1 print(f"After: num1={num1}, num2={num2}") ```

Exercise 3: Multiple Assignment Practice
Create a tuple coordinates = (5, 10, 15) and unpack into x, y, z. Also create a list data = [100, 200, 300, 400, 500] and use extended unpacking to get first, middle, last (where middle is a list of middle three).

Sample Solution ```python coordinates = (5, 10, 15) x, y, z = coordinates print(x, y, z)

data = [100, 200, 300, 400, 500] first, *middle, last = data print(first, middle, last) # 100, [200, 300, 400], 500

</details> **Exercise 4: Dynamic Typing Experiment** Write a program that: 1. Creates a variable `var` and assigns it the value `10`. 2. Prints `var` and its type. 3. Reassigns `var` to `"Python"`. 4. Prints `var` and its type. 5. Reassigns `var` to `[1, 2, 3]`. 6. Prints `var` and its type. 7. Reassigns `var` to `True`. 8. Prints `var` and its type. 9. Explain in comments why this is possible in Python. **Exercise 5: Aliasing vs. Copying** Write a script that demonstrates: 1. Creating a list `original = [10, 20, 30]`. 2. Creating a reference `alias = original`. 3. Creating an independent copy `copy = original[:]`. 4. Modifying the first element of `alias` to 99. 5. Printing `original`, `alias`, and `copy` to show: - `original` and `alias` are the same. - `copy` is independent. 6. Now modify the first element of `copy` to 55. 7. Print all three lists again to confirm `original` hasn't changed. ## 5. Homework Questions (Deep Thinking) Here are the rewritten exercises with comprehensive sample answers added. **Exercise 4: Dynamic Typing Experiment** Write a program that: 1. Creates a variable `var` and assigns it the value `10`. 2. Prints `var` and its type. 3. Reassigns `var` to `"Python"`. 4. Prints `var` and its type. 5. Reassigns `var` to `[1, 2, 3]`. 6. Prints `var` and its type. 7. Reassigns `var` to `True`. 8. Prints `var` and its type. 9. Explain in comments why this is possible in Python. <details><summary>Sample Answer</summary> ```python """ DYNAMIC TYPING EXPERIMENT Demonstrating Python's dynamic typing feature """ print("=" * 60) print("DYNAMIC TYPING EXPERIMENT") print("=" * 60) # Step 1 & 2: Assign integer and print var = 10 print(f"Step 1 & 2 - var = {var}, type = {type(var)}") # Step 3 & 4: Reassign to string var = "Python" print(f"Step 3 & 4 - var = '{var}', type = {type(var)}") # Step 5 & 6: Reassign to list var = [1, 2, 3] print(f"Step 5 & 6 - var = {var}, type = {type(var)}") # Step 7 & 8: Reassign to boolean var = True print(f"Step 7 & 8 - var = {var}, type = {type(var)}") print("\n" + "=" * 60) print("EXPLANATION (in comments)") print("=" * 60) """ EXPLANATION: This code works because Python is a dynamically typed language. The key concepts are: 1. Variables are just names (references) to objects in memory. They do not have a fixed type themselves. 2. The type of a variable is determined by the object it currently references. When we reassign a variable, we are changing what object it points to. 3. Python does not require variable type declarations. Unlike statically typed languages (like Java or C++), where you must declare int x = 10; and cannot later assign x = "Hello", Python allows this because it checks types at runtime. 4. Under the hood, when we do: var = 10 → var points to an integer object var = "Python" → var now points to a string object The old integer object is garbage-collected if no other references exist. 5. This flexibility makes Python easier to use but requires careful programming to avoid type-related runtime errors. """ print("\nAdditional demonstration:") # Showing that we can even change type within an expression value = 5 print(f"value = {value}, type: {type(value)}") value = value + 3.14 # int + float → float print(f"value = {value}, type: {type(value)}") # Further examples of dynamic typing def print_value(x): """A function that works with any type.""" print(f"Received: {x}, type: {type(x)}") print("\nFunction with dynamic parameter:") print_value(100) print_value("Dynamic!") print_value([1, 2, 3]) print_value(True) print("\n" + "=" * 60) print("KEY TAKEAWAYS") print("=" * 60) print(" • Python variables are dynamically typed") print(" • Variables can be reassigned to any type at any time") print(" • The type is determined by the value, not the variable") print(" • This is possible because Python is an interpreted language") print(" • Type checking happens at runtime (not compile time)") print(" • This flexibility comes with responsibility to avoid type errors") print("=" * 60)

Sample Output:

============================================================ DYNAMIC TYPING EXPERIMENT ============================================================ Step 1 & 2 - var = 10, type = <class 'int'> Step 3 & 4 - var = 'Python', type = <class 'str'> Step 5 & 6 - var = [1, 2, 3], type = <class 'list'> Step 7 & 8 - var = True, type = <class 'bool'> ============================================================ EXPLANATION (in comments) ============================================================ Additional demonstration: value = 5, type: <class 'int'> value = 8.14, type: <class 'float'> Function with dynamic parameter: Received: 100, type: <class 'int'> Received: Dynamic!, type: <class 'str'> Received: [1, 2, 3], type: <class 'list'> Received: True, type: <class 'bool'> ============================================================ KEY TAKEAWAYS ============================================================ • Python variables are dynamically typed • Variables can be reassigned to any type at any time • The type is determined by the value, not the variable • This is possible because Python is an interpreted language • Type checking happens at runtime (not compile time) • This flexibility comes with responsibility to avoid type errors ============================================================

Explanation of Dynamic Typing:

  1. No Type Declaration: In Python, you don't declare int x; you just write x = 10.

  2. Type is Runtime Property: The type of x is determined by the value it holds at any given moment.

  3. Reassignment Changes Type: When you assign a new value of a different type, the variable's type changes.

  4. Behind the Scenes: Each object in Python has a type tag. Variables are just references that can point to any object.

  5. Advantages: More flexible, less boilerplate, easier prototyping.

  6. Disadvantages: Can lead to type-related bugs if not careful (e.g., treating a string as a number).

Exercise 5: Aliasing vs. Copying

Write a script that demonstrates:

  1. Creating a list original = [10, 20, 30].
  2. Creating a reference alias = original.
  3. Creating an independent copy copy = original[:].
  4. Modifying the first element of alias to 99.
  5. Printing original, alias, and copy to show:
  6. Now modify the first element of copy to 55.
  7. Print all three lists again to confirm original hasn't changed.
Sample Answer
""" ALIASING VS. COPYING Demonstrating the difference between reference assignment and creating a copy """ print("=" * 60) print("ALIASING VS. COPYING") print("=" * 60) # --- Step 1: Create the original list --- original = [10, 20, 30] print(f"Step 1 - original: {original}") print(f" ID of original: {id(original)}") # --- Step 2: Create an alias (reference) --- alias = original print(f"\nStep 2 - alias = original") print(f" alias: {alias}") print(f" ID of alias: {id(alias)}") print(f" Are they the same object? {original is alias}") # True # --- Step 3: Create an independent copy using slicing --- copy = original[:] print(f"\nStep 3 - copy = original[:]") print(f" copy: {copy}") print(f" ID of copy: {id(copy)}") print(f" Are they the same object? {original is copy}") # False print("\n" + "-" * 60) print("BEFORE MODIFICATION") print("-" * 60) print(f"original: {original}") print(f"alias: {alias}") print(f"copy: {copy}") # --- Step 4: Modify the alias (affects original) --- alias[0] = 99 print("\n" + "-" * 60) print("STEP 4: AFTER MODIFYING alias[0] = 99") print("-" * 60) print(f"original: {original}") # Changed! print(f"alias: {alias}") # Changed! print(f"copy: {copy}") # Unchanged (independent) # --- Step 5: Show that original and alias are the same --- print("\n" + "-" * 60) print("STEP 5: VERIFICATION") print("-" * 60) print(f"'original is alias' → {original is alias}") # True print(f"'original is copy' → {original is copy}") # False # --- Step 6: Modify the copy (does NOT affect original) --- copy[0] = 55 print("\n" + "-" * 60) print("STEP 6: AFTER MODIFYING copy[0] = 55") print("-" * 60) print(f"original: {original}") # Still [99, 20, 30] print(f"alias: {alias}") # Still [99, 20, 30] print(f"copy: {copy}") # Changed to [55, 20, 30] # --- Step 7: Confirm original hasn't changed --- print("\n" + "-" * 60) print("STEP 7: FINAL CHECK - original unchanged?") print("-" * 60) print(f"original: {original}") print(f"copy: {copy}") print(f"Are original and copy equal? {original == copy}") # False print(f"Did original change? {'✅ No' if original == [99, 20, 30] else '❌ Yes'}") print("\n" + "=" * 60) print("MEMORY DIAGRAM (CONCEPTUAL)") print("=" * 60) # Visual representation of memory print(""" After Step 1-3: original ──→ [10, 20, 30] (Object A at address 1000) alias ──→ [10, 20, 30] (Same object A - alias points to same address) copy ──→ [10, 20, 30] (Object B at address 2000 - independent copy) After Step 4 (alias[0] = 99): original ──→ [99, 20, 30] (Object A modified in-place) alias ──→ [99, 20, 30] (Still points to Object A - sees the change) copy ──→ [10, 20, 30] (Object B unchanged - independent) After Step 6 (copy[0] = 55): original ──→ [99, 20, 30] (Object A remains as modified) alias ──→ [99, 20, 30] (Object A remains as modified) copy ──→ [55, 20, 30] (Object B modified in-place - independent) """) print("=" * 60) print("KEY TAKEAWAYS") print("=" * 60) print(" • 'alias = original' creates an alias (both point to same object)") print(" • 'copy = original[:]' creates an independent copy (new object)") print(" • Modifying the alias modifies the original (shared object)") print(" • Modifying the copy does NOT affect the original") print(" • Use 'is' to check object identity (same object) vs '==' (same value)") print(" • Always copy mutable objects when you need independent data") print("=" * 60) print("\n" + "=" * 60) print("ADDITIONAL COPY METHODS") print("=" * 60) # More ways to create independent copies print("\nCreating independent copies of a list:") original = [10, 20, 30] # Method 1: Slicing (most common) copy1 = original[:] print(f" Method 1 - original[:]: {copy1} (id: {id(copy1)})") # Method 2: list() constructor copy2 = list(original) print(f" Method 2 - list(original): {copy2} (id: {id(copy2)})") # Method 3: .copy() method (Python 3.3+) copy3 = original.copy() print(f" Method 3 - original.copy(): {copy3} (id: {id(copy3)})") # Method 4: copy module (for deep copying, beyond scope) # import copy # copy4 = copy.deepcopy(original) # For nested structures print("\nAll copies are independent:") print(f" original is copy1? {original is copy1}") # False print(f" original is copy2? {original is copy2}") # False print(f" original is copy3? {original is copy3}") # False print(" All have different object identities!") print("\n" + "=" * 60) print("WHEN TO USE ALIAS VS. COPY") print("=" * 60) print(""" Use ALIAS when: • You want multiple variables to reference the same data • You want to pass a mutable object to a function that should modify it • You are working with large data and want to avoid copying overhead Use COPY when: • You need to preserve the original data • You want to modify data without affecting other references • You are passing data to a function that should not modify the original """) print("=" * 60)

Sample Output:

============================================================ ALIASING VS. COPYING ============================================================ Step 1 - original: [10, 20, 30] ID of original: 140734567890123 Step 2 - alias = original alias: [10, 20, 30] ID of alias: 140734567890123 Are they the same object? True Step 3 - copy = original[:] copy: [10, 20, 30] ID of copy: 140734567890456 Are they the same object? False ------------------------------------------------------------ BEFORE MODIFICATION ------------------------------------------------------------ original: [10, 20, 30] alias: [10, 20, 30] copy: [10, 20, 30] ------------------------------------------------------------ STEP 4: AFTER MODIFYING alias[0] = 99 ------------------------------------------------------------ original: [99, 20, 30] alias: [99, 20, 30] copy: [10, 20, 30] ------------------------------------------------------------ STEP 5: VERIFICATION ------------------------------------------------------------ 'original is alias' → True 'original is copy' → False ------------------------------------------------------------ STEP 6: AFTER MODIFYING copy[0] = 55 ------------------------------------------------------------ original: [99, 20, 30] alias: [99, 20, 30] copy: [55, 20, 30] ------------------------------------------------------------ STEP 7: FINAL CHECK - original unchanged? ------------------------------------------------------------ original: [99, 20, 30] copy: [55, 20, 30] Are original and copy equal? False Did original change? ✅ No ============================================================ MEMORY DIAGRAM (CONCEPTUAL) ============================================================ After Step 1-3: original ──→ [10, 20, 30] (Object A at address 1000) alias ──→ [10, 20, 30] (Same object A - alias points to same address) copy ──→ [10, 20, 30] (Object B at address 2000 - independent copy) After Step 4 (alias[0] = 99): original ──→ [99, 20, 30] (Object A modified in-place) alias ──→ [99, 20, 30] (Still points to Object A - sees the change) copy ──→ [10, 20, 30] (Object B unchanged - independent) After Step 6 (copy[0] = 55): original ──→ [99, 20, 30] (Object A remains as modified) alias ──→ [99, 20, 30] (Object A remains as modified) copy ──→ [55, 20, 30] (Object B modified in-place - independent) ============================================================ KEY TAKEAWAYS ============================================================ • 'alias = original' creates an alias (both point to same object) • 'copy = original[:]' creates an independent copy (new object) • Modifying the alias modifies the original (shared object) • Modifying the copy does NOT affect the original • Use 'is' to check object identity (same object) vs '==' (same value) • Always copy mutable objects when you need independent data ============================================================ ============================================================ ADDITIONAL COPY METHODS ============================================================ Creating independent copies of a list: Method 1 - original[:]: [10, 20, 30] (id: 140734567890789) Method 2 - list(original): [10, 20, 30] (id: 140734567890123) Method 3 - original.copy(): [10, 20, 30] (id: 140734567890456) All copies are independent: original is copy1? False original is copy2? False original is copy3? False All have different object identities! ============================================================ WHEN TO USE ALIAS VS. COPY ============================================================ Use ALIAS when: • You want multiple variables to reference the same data • You want to pass a mutable object to a function that should modify it • You are working with large data and want to avoid copying overhead Use COPY when: • You need to preserve the original data • You want to modify data without affecting other references • You are passing data to a function that should not modify the original ============================================================

Explanation:

Key Concepts:

  1. Alias (alias = original):

    • Both variables point to the same object in memory.
    • Modifying one affects the other.
  2. Independent Copy (copy = original[:] or list(original) or original.copy()):

    • A new object is created with the same values.
    • Modifying the copy does not affect the original.
  3. Object Identity (is):

    • original is aliasTrue (same object)
    • original is copyFalse (different objects)
  4. Value Equality (==):

    • original == copyTrue (same contents at creation)
    • After modification, original == copy may become False.
  5. Memory Diagram:

    • Visual representation of objects and references.
    • Helps understand the difference between sharing and copying.

Why This Matters:

  1. Avoiding Unintended Side Effects: If you have multiple variables referencing the same list, changing one can break other parts of your code.

  2. Function Arguments: Passing a list to a function can result in the function modifying the original list unless you pass a copy.

  3. Data Integrity: When you need to keep an original version, always make a copy before modifying.

  4. Performance: Aliasing is more memory-efficient because it doesn't create new objects. Use it when you intentionally want to share data.

  5. Common Bugs: Many beginners are surprised when modifying a "copy" that was actually an alias. This exercise helps avoid that trap.

6. Summary Checklist (For Student Self-Review)

7. Additional Challenge: The Assignment Puzzle

Learning Objective

Write a program that takes a list of values and swaps every pair in the list (e.g., [1, 2, 3, 4] → [2, 1, 4, 3]).

Instructions (Advanced Homework Bonus): Write a program that:

  1. Creates a list numbers = [10, 20, 30, 40, 50, 60].
  2. Using a loop (preview of iteration) and multiple assignment, swap adjacent pairs.
  3. Print the list before and after.
  4. Challenge: Can you do it in one line using list comprehension? (Advanced, but encourage research).

Sample Output:

Before: [10, 20, 30, 40, 50, 60] After: [20, 10, 40, 30, 60, 50]

Previous | Tutorial index | Next