Lab 1: The “Type Inspector” Check the types of various DevOps data points.
api_response = {"status": 200, "body": "OK"} # dict
server_list = ["10.0.0.1", "10.0.0.2"] # list
is_secure = True # bool
max_retries = 5 # int
latency = 0.45 # float
print(f"API is {type(api_response)}")
print(f"Latency is {type(latency)}")
Lab 2: The “Strong Typing” Crash Try to add text and numbers.
port = 8080
msg = "Server running on port "
# print(msg + port) # CRASH: TypeError: can only concatenate str (not "int") to str
# Fix: Casting (converting)
print(msg + str(port)) # Works!
Lab 3: Sets for Uniqueness DevOps Scenario: You scanned logs and found duplicate IPs. Clean them up.
dirty_ips = ["192.168.1.1", "10.0.0.5", "192.168.1.1", "10.0.0.5"]
unique_ips = set(dirty_ips)
print(unique_ips)
# Output: {'10.0.0.5', '192.168.1.1'} (Duplicates gone instantly!)
Lab 4: The “JSON Config” Challenge (Dictionaries)
Scenario: You are working with a JSON configuration file (represented as a Python Dictionary) for a Kubernetes Pod. You need to safely extract the “Image” name.
- The Trap: Accessing a key that doesn’t exist crashes the script with a
KeyError. - The Fix: Use the
.get()method.
# A typical nested dictionary (like a JSON file)
k8s_pod = {
"metadata": {
"name": "nginx-pod",
"namespace": "production"
},
"spec": {
"containers": [
{"name": "nginx", "image": "nginx:1.14.2"}
]
}
}
# 1. The Risky Way (Direct Access)
# If 'status' key is missing, this line crashes the script!
# print(k8s_pod["status"]["phase"]) # Uncommenting this causes KeyError
# 2. The Safe Way (Using .get)
# Returns 'None' or a default value instead of crashing
pod_phase = k8s_pod.get("status", "Unknown")
print(f"Pod Phase: {pod_phase}")
# 3. Accessing Nested Data
image_name = k8s_pod["spec"]["containers"][0]["image"]
print(f"Container Image: {image_name}")
- Architect Insight: In automation pipelines, never assume a key exists. Always use
.get()to prevent your entire pipeline from failing just because one optional field was missing.
Lab 5: The “Boolean Trap” (Type Casting Danger)
Scenario: You are reading Environment Variables to enable DEBUG mode.
- The Problem: Environment variables are always Strings.
- The Trap:
bool("False")evaluates toTruein Python! Why? Because any non-empty string is “Truthy”.
# Simulation of reading an Env Variable
env_debug_value = "False" # This is what you get from os.environ
# BEGINNER MISTAKE:
is_debug_on = bool(env_debug_value)
print(f"Is Debug ON? {is_debug_on}")
# Output: True (Wait, what?? We set it to False!)
# ARCHITECT FIX:
# Compare the string value directly
real_debug_status = env_debug_value.lower() == "true"
print(f"Is Debug ON (Fixed)? {real_debug_status}")
# Output: False (Correct)
- Why this matters: I have seen production servers accidentally run in “Debug Mode” (exposing sensitive data) because of this specific misunderstanding of Python Data Types.
Lab 6: The “Log Parser” (String Splitting & Lists)
Scenario: You have a raw log line from a firewall. You need to extract the IP Address and the Error Code.
- Concept: Strings are just sequences of characters. You can split them into a List.
raw_log = "2024-01-20 10:00:01 | ERROR | 192.168.1.50 | Connection Refused"
# Split the string by the separator " | "
log_parts = raw_log.split(" | ")
print(f"Parsed Data: {log_parts}")
print(f"Type of data: {type(log_parts)}")
# Extract specific fields using List Indexing
timestamp = log_parts[0]
severity = log_parts[1]
ip_address = log_parts[2]
print(f"Alert! Malicious traffic from {ip_address} with severity {severity}")
Output:
Parsed Data: ['2024-01-20 10:00:01', 'ERROR', '192.168.1.50', 'Connection Refused']
Alert! Malicious traffic from 192.168.1.50 with severity ERROR
Lab 7: The “Immutable Credentials” (Tuple vs List)
Scenario: You are storing database credentials in your script.
- Goal: Ensure that no other part of the script can accidentally change the port number or password.
- Solution: Use a Tuple.
# Tuple: (Host, Port, DB_Name)
db_config = ("db.prod.local", 5432, "users_db")
print(f"Connecting to {db_config[0]} on port {db_config[1]}...")
# Try to hack the port (Simulating a bug in code)
try:
db_config[1] = 8080 # Trying to change 5432 to 8080
except TypeError as e:
print(f"Security Blocked: {e}")
# Output: 'tuple' object does not support item assignment
- Architect Insight: Using Tuples communicates “Intent”. It tells other developers (and the future you): “Do not touch this data, it is constant.”
Lab 8: Identifying Binary Data (Bytes)
Scenario: You are checking if a file is an image or a text file by looking at the header (magic bytes).
- Concept:
b"..."denotes a Byte Literal, distinct from a standard String.
# A standard string
text_header = "PNG"
# A byte string (Machine readable data)
binary_header = b"PNG"
print(f"Type of text: {type(text_header)}") # <class 'str'>
print(f"Type of binary: {type(binary_header)}") # <class 'bytes'>
# They are NOT equal
print(f"Are they equal? {text_header == binary_header}") # False