Lab: The “Immutable” Log Fixer
Scenario: You have received a server log where the server name was recorded incorrectly as "server-production". Due to a policy change, all servers must start with "SRV-". Since you cannot change the string in place, you must reconstruct it.
Task:
- Check if the string starts with “server”.
- Create a new string that replaces “server” with “SRV”.
- Verify the new string is actually a new object in memory.
# Lab Code
# 1. Old String
old_log = "server-production-01"
print(f"Original: {old_log} | ID: {id(old_log)}")
# 2. Transformation (Since we can't do old_log[0:6] = "SRV")
# We use slicing to keep everything AFTER index 6 ("-production-01")
remaining_part = old_log[6:]
# Construct New String
new_log = "SRV" + remaining_part
# 3. Verification
print(f"Fixed: {new_log} | ID: {id(new_log)}")
# Logic Check
if id(old_log) != id(new_log):
print("Success: A new immutable string object was created.")
else:
print("Error: IDs match.")Lab 1: Visualizing Immutability (Memory Lab)
Task: Prove that modifying a string changes its memory location.
# Lab 1: The Identity Check
user_role = "admin"
print(f"Original Role: {user_role} | Memory Address: {id(user_role)}")
# Attempt to 'modify' (concatenation)
user_role = user_role + "_sys"
print(f"New Role: {user_role} | Memory Address: {id(user_role)}")
# Observation: The memory addresses are totally different.
# Proof: The original "admin" string was NOT changed; a new "admin_sys" was created.
Lab 2: Iteration for Security (Password Strength)
Task: Use the Iterable nature of strings to count digits in a password.
# Lab 2: The Strength Checker
password = "SecurePass123!"
digit_count = 0
# Iterating through the string character by character
for char in password:
# Check if the character is a number
if char.isdigit():
digit_count += 1
print(f"Password '{password}' contains {digit_count} numbers.")
# Output: Password 'SecurePass123!' contains 3 numbers.
Lab 3: Ordered Slicing (Log Extraction)
Task: Use the Ordered nature to extract specific data from a structured string.
# Lab 3: The Order Extractor
# Standard Format: [Date] [Level] Message
log_entry = "[2026-01-28] [ERROR] DB Connection Failed"
# Because strings are ordered, we know exactly where the Date is relative to brackets
date_part = log_entry[1:11]
print(f"Date of Incident: {date_part}")
# Output: 2026-01-28
Lab 1: The “Secret Key” Masker (Immutability & Ordering)
Concept: Since strings are Immutable, you cannot just overwrite the middle characters of a password to hide them. You must use Slicing (Order) to cut the head and tail, and create a new string with stars in the middle.
Scenario: You are building a logging system. When an API Key is printed to the logs, it must be masked so that only the first 4 and last 4 characters are visible.
Input: API_KEY = "SK_live_51Mz9AaT7bCq8Zp2"
Task:
- Extract the first 4 characters.
- Extract the last 4 characters.
- Calculate how many hidden characters are in the middle.
- Create a new masked string.
# Lab 1 Solution
api_key = "SK_live_51Mz9AaT7bCq8Zp2"
# 1. Slice the Start (Indices 0 to 3)
prefix = api_key[0:4]
# 2. Slice the End (Last 4 characters)
suffix = api_key[-4:]
# 3. Calculate masking length
# Total length - (length of prefix + length of suffix)
mask_length = len(api_key) - (len(prefix) + len(suffix))
# 4. Construct the NEW string (Concatenation)
masked_key = prefix + ("*" * mask_length) + suffix
print(f"Original: {api_key}")
print(f"Masked: {masked_key}")
# Verification of Immutability:
# api_key is still the same. 'masked_key' is a new object.
print(f"Original is untouched: {api_key}")
Lab 2: The Permission Analyzer (Iterable)
Concept: Strings are Iterable. You can loop through them to check every single character.
Scenario: In Linux, file permissions are often shown as strings like rwxr-xr-x (Read, Write, Execute). You need to write a script that iterates through this string and raises a “Security Alert” if the Write (‘w’) permission is found more than once (meaning it’s too open).
Input: permissions = "rwxrwxrwx" (777 – Very Dangerous!)
Task:
- Loop through the string character by character.
- Count how many times
'w'appears. - If count > 1, print a red alert.
# Lab 2 Solution
permissions = "rwxrwxrwx"
write_count = 0
# 1. Iterate through the string
for char in permissions:
# 2. Check condition
if char == 'w':
write_count = write_count + 1
# 3. Decision Logic
print(f"Analyzing permissions: {permissions}")
if write_count > 1:
print(f"SECURITY ALERT: Write permission found {write_count} times! Too dangerous.")
else:
print("Permissions look safe.")
Lab 3: The Version Extractor (Ordered)
Concept: Strings are Ordered. We rely on specific positions (indexes) to extract meaningful data.
Scenario: You have a list of backup files named backup_2026_v1.tar.gz. You need to extract just the Year (2026) to organize them into folders. You know the format is always backup_YEAR_....
Task: Use slicing with specific indices to extract the year.
# Lab 3 Solution
filename = "backup_2026_v1.tar.gz"
# We know the format:
# b a c k u p _ 2 0 2 6 ...
# 0 1 2 3 4 5 6 7 8 9 10
# The year starts at index 7 and ends at index 11 (exclusive)
year = filename[7:11]
print(f"Processing File: {filename}")
print(f"Extracted Year: {year}")
# Advanced Architect Tip:
# If the filename length changes, slicing by hard numbers is risky.
# Better to use .split('_') if the separator is consistent.
parts = filename.split('_') # ['backup', '2026', 'v1.tar.gz']
print(f"Safer Extraction: {parts[1]}")
Lab 4: The “Reverse” Encryption (Ordered)
Concept: Python’s unique slicing capability [::-1] allows you to reverse the Order of a string instantly.
Scenario: You need to send a simple obfuscated message over a network so it isn’t readable by a casual glance. You decide to reverse the string.
Task:
- Take a message string.
- Create a reversed version.
- Reverse it back to prove it works.
# Lab 4 Solution
message = "DevSecOps"
# 1. Reverse the string using negative step slicing
# Syntax: [start : end : step]
# Step -1 means "walk backwards"
encrypted = message[::-1]
print(f"Original: {message}")
print(f"Encrypted: {encrypted}")
# 2. Decrypt (Reverse the reversed string)
decrypted = encrypted[::-1]
print(f"Decrypted: {decrypted}")
# Validation
if message == decrypted:
print("Integrity Check Passed.")