Python Assigning Values Lab

Lab 1: The Swapper

# Traditional way (Don't do this in Python)
a = 5
b = 10
temp = a
a = b
b = temp
print(a, b)

# Pythonic way (Do this!)
x = 50
y = 100
x, y = y, x
print(f"x is now {x}, y is now {y}")

Lab 2: Advanced Unpacking

server_config = ("192.168.1.1", 8080, "Production", "AWS", "Linux")
# Extract IP and Port, keep the rest as metadata
ip, port, *metadata = server_config

print(f"Connecting to {ip} on {port}")
print(f"Server Info: {metadata}")

Lab 3: The “Mutable Assignment” Trap (Critical)

Scenario: You want to initialize three different server lists for Development, QA, and Production. You decide to use “Chained Assignment” to save time.

  • The Trap: When you assign a Mutable object (like a List) using a = b = [], you aren’t creating three lists. You are creating one list with three tags. If you add a server to Dev, it magically appears in Prod too!
print("--- The Trap ---")
# BAD PRACTICE for Mutable Objects
dev_servers = qa_servers = prod_servers = []

# We add a server ONLY to 'dev_servers'
dev_servers.append("dev-db-01")

print(f"Dev:  {dev_servers}")
print(f"Prod: {prod_servers}") 
# Output: Prod: ['dev-db-01'] 
# DISASTER! Production list got modified because they are the SAME object.

print("\n--- The Fix ---")
# CORRECT PRACTICE
# Create independent lists
dev_servers = []
qa_servers = []
prod_servers = []

dev_servers.append("dev-api-01")
print(f"Dev:  {dev_servers}")
print(f"Prod: {prod_servers}") 
# Output: Prod: [] (Clean and Safe)
  • Architect Insight: Never use chained assignment (x = y = []) for lists or dictionaries. Only use it for immutable things like numbers, booleans, or strings (x = y = 0).

Lab 4: Log Parsing with Star Operator (*)

Scenario: You are parsing raw access logs from an Apache/Nginx server. The log format is [Timestamp, IP, Method, Path, ...UserAgent...].

  • Challenge: The User Agent string at the end might be split into many parts by spaces, or it might be short. You don’t know the length.
  • Solution: Use the Star Operator to grab “everything else” into a list.
raw_log_line = ["2024-01-20", "192.168.1.5", "GET", "/login", "Mozilla/5.0", "(Windows", "NT", "10.0)"]

# We want specific fields for the first 4 items.
# We want to bundle the rest (User Agent) into one variable.
timestamp, client_ip, method, path, *user_agent_parts = raw_log_line

print(f"Alert: {client_ip} tried to access {path}")

# Reconstruct the User Agent string from the list
full_user_agent = " ".join(user_agent_parts)
print(f"User Agent: {full_user_agent}")

Output:

Alert: 192.168.1.5 tried to access /login
User Agent: Mozilla/5.0 (Windows NT 10.0)

Lab 5: The “Ignore” Convention (Using _)

Scenario: You are calling a function (like an AWS SDK method) that returns a tuple with 3 values: (Status, Message, RequestID).

  • Goal: You only care about the Status. You don’t want to clutter your code with variables named msg or req_id that you never use.
  • Solution: Use the underscore _ as a “trash can” variable.
# Simulating a function that returns multiple values
def reboot_instance():
    return ("SUCCESS", "Reboot initiated", "req-abc-123")

# Standard Unpacking:
# status, msg, req_id = reboot_instance() -> Wastes memory if we don't use msg/req_id

# Professional Unpacking:
# Use '_' for values you want to ignore.
status, _, _ = reboot_instance()

print(f"Operation Status: {status}")
  • Architect Insight: This is highly recommended by PEP 8 (Python’s style guide). It tells other developers: “I know these values exist, but I am intentionally ignoring them.”

Lab 6: Deep Dive into Reference Counting

Scenario: Let’s prove that variables are just “Tags” and see exactly when Python decides to delete an object.

import sys

# 1. Create an object "CyberSecurity"
tag_1 = "CyberSecurity" 

# 2. Check references
# Note: getrefcount returns a higher number because the function call itself creates a temporary reference.
print(f"Initial Refs: {sys.getrefcount(tag_1)}") 

# 3. Add a second tag
tag_2 = tag_1
print(f"Refs after tag_2: {sys.getrefcount(tag_1)}") # Count increases

# 4. Remove tags
del tag_1
print("Deleted tag_1...")

# The object "CyberSecurity" is NOT deleted yet because tag_2 still holds it.
print(f"tag_2 still holds: {tag_2}")

# 5. Remove final tag
del tag_2
# Now the reference count hits 0. The Garbage Collector will eat the object immediatel

Output

Initial Refs: 4
Refs after tag_2: 5
Deleted tag_1...
tag_2 still holds: CyberSecurity

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top