The Ops Engineer's Toolkit
Before you can automate infrastructure, you need to know how to hold information about it. Python has four built-in data structures that you will use constantly in ops work. Choosing the right one for the job makes your code cleaner and your logic more correct.
1. Lists — Ordered, Mutable Sequences
A list is like a numbered to-do list. Items have a position (index), you can add or remove items, and duplicates are allowed.
# A list of servers to reboot, in order
servers = ["web-01", "db-01", "cache-01"]
# Access by index (zero-based)
print(servers[0]) # "web-01"
# Add a server
servers.append("web-02")
# Iterate
for server in servers:
print(f"Rebooting {server}...")
Ops use cases: A list of EC2 instance IDs to terminate, a sequence of deployment steps to execute in order, a list of IP addresses to add to a firewall rule.
2. Dictionaries — Key-Value Pairs
A dictionary is like a phone book or a JSON object. You look up a unique key to retrieve its associated value. Keys must be unique; values can be anything.
# Configuration for a single server
server_config = {
"hostname": "web-01",
"ip": "10.0.0.5",
"os": "Ubuntu 22.04",
"port": 22
}
# Access by key
print(server_config["ip"]) # "10.0.0.5"
# Safe access (returns None if key missing, avoids KeyError)
print(server_config.get("region")) # None
# Add or update a key
server_config["region"] = "us-east-1"
Ops use cases: Storing parsed JSON from an API response, mapping hostnames to IP addresses, holding environment-specific configuration values.
3. Sets — Unique, Unordered Collections
A set is like a bag of marbles where duplicates are automatically discarded. Order is not preserved, and every element is guaranteed to be unique.
# Collecting unique error codes from a log file
unique_errors = set()
log_lines = ["404", "200", "500", "404", "503", "500", "200"]
for code in log_lines:
unique_errors.add(code)
print(unique_errors) # {'200', '404', '500', '503'} — no duplicates
Sets also support mathematical operations that are extremely useful for comparing infrastructure states:
expected_servers = {"web-01", "web-02", "db-01"}
running_servers = {"web-01", "db-01", "cache-01"}
missing = expected_servers - running_servers # {"web-02"} — should be running but isn't
extra = running_servers - expected_servers # {"cache-01"} — running but not expected
Ops use cases: Deduplicating IP addresses from logs, finding the difference between expected and actual infrastructure state, checking for overlap between security groups.
4. Tuples — Immutable Sequences
A tuple is like a list, but once created it cannot be changed. This immutability is a feature, not a limitation — it signals to anyone reading the code that this data should not be modified.
# Data center coordinates — should never change at runtime
datacenter_coords = (37.7749, -122.4194) # (latitude, longitude)
# Tuples are commonly used for multiple return values
def get_server_info():
return ("web-01", "10.0.0.5", 22)
hostname, ip, port = get_server_info() # tuple unpacking
Ops use cases: Fixed configuration constants, returning multiple values from a function, dictionary keys (lists cannot be dictionary keys, but tuples can).
Choosing the right structure: If order matters and duplicates are allowed, use a list. If you need to look things up by name, use a dict. If you need uniqueness or set math, use a set. If the data should never change, use a tuple.