Practical Example: Nested Network Device Configs

🏷️ Dictionaries / Nested Dictionaries

đź§­ Context Introduction

As you begin working with network automation, you'll quickly discover that real-world device configurations are rarely flat and simple. A single switch or router contains multiple interfaces, each with its own IP address, VLAN assignment, and status. This hierarchical data is best represented using nested dictionaries—dictionaries inside other dictionaries. In this guide, we'll walk through a practical example of modeling a network device's configuration using nested dictionaries, then show how to access, update, and iterate over that data.


⚙️ Why Nested Dictionaries for Network Configs?

  • Real-world structure: A device has interfaces; each interface has properties (IP, VLAN, status). This is a natural parent-child relationship.
  • Efficient lookups: Instead of looping through flat lists, you can access specific interface details directly by key.
  • Easy to update: Need to change the IP on interface GigabitEthernet0/1? You can do it in one line without touching other data.
  • Readable and maintainable: Nested dictionaries mirror how engineers think about device configurations—organized by device, then interface, then property.

🛠️ Building a Nested Device Config

Let's model a single network switch with two interfaces. We'll create a dictionary where the top-level key is the device hostname, and the value is another dictionary containing interface names as keys, each pointing to a dictionary of properties.

Example structure (conceptual): - Top-level key: "switch-01" - Inside that, a key "interfaces" with value being another dictionary - Inside interfaces, keys like "GigabitEthernet0/1" and "GigabitEthernet0/2" - Each interface has keys: "ip_address", "vlan", "status"

How to build it in Python: - Start with an empty dictionary: device_config = {} - Add the device name as a key with an empty dictionary as value: device_config["switch-01"] = {} - Inside that, add an "interfaces" key with another empty dictionary: device_config["switch-01"]["interfaces"] = {} - Now add each interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"] = {"ip_address": "10.0.1.1", "vlan": 10, "status": "up"} - Repeat for the second interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/2"] = {"ip_address": "10.0.2.1", "vlan": 20, "status": "down"}

The final structure looks like this (written as a single assignment for clarity): - device_config = {"switch-01": {"interfaces": {"GigabitEthernet0/1": {"ip_address": "10.0.1.1", "vlan": 10, "status": "up"}, "GigabitEthernet0/2": {"ip_address": "10.0.2.1", "vlan": 20, "status": "down"}}}}


🕵️ Accessing Nested Data

To retrieve specific values, chain the keys in order from outer to inner.

Examples of accessing data: - Get the IP address of the first interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"]["ip_address"] → returns "10.0.1.1" - Get the VLAN of the second interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/2"]["vlan"] → returns 20 - Get the entire dictionary for the first interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"] → returns {"ip_address": "10.0.1.1", "vlan": 10, "status": "up"}

What happens if a key doesn't exist? - Python raises a KeyError. To avoid this, use the .get() method: device_config.get("switch-01", {}).get("interfaces", {}).get("GigabitEthernet0/3", "Not found") → returns "Not found" instead of crashing.


📊 Updating Nested Values

Updating a value in a nested dictionary is straightforward—just assign a new value to the full key path.

Examples of updates: - Change the IP address on GigabitEthernet0/1: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"]["ip_address"] = "10.0.1.100" - Change the status of GigabitEthernet0/2 to "up": device_config["switch-01"]["interfaces"]["GigabitEthernet0/2"]["status"] = "up" - Add a new property (e.g., description) to an interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"]["description"] = "Uplink to core"

Adding a new interface entirely: - device_config["switch-01"]["interfaces"]["GigabitEthernet0/3"] = {"ip_address": "10.0.3.1", "vlan": 30, "status": "admin down"}


🔄 Iterating Over Nested Data

To process all interfaces on a device, you'll need nested loops—one for devices, one for interfaces.

How to loop through all interfaces: - Outer loop: for device_name, device_data in device_config.items(): — this gives you each device name and its data dictionary - Inner loop: for interface_name, interface_props in device_data["interfaces"].items(): — this gives you each interface name and its properties dictionary - Inside the inner loop, you can access individual properties: interface_props["ip_address"], interface_props["vlan"], interface_props["status"]

Practical output example (not code, just the logic): - For each device, print the device name - For each interface on that device, print the interface name, its IP, VLAN, and status - This lets you generate a report of all interfaces across all devices in one go


đź§© Comparison: Flat vs. Nested Structures

Feature Flat Dictionary Nested Dictionary
Example key "switch-01_Gig0/1_ip" ["switch-01"]["interfaces"]["Gig0/1"]["ip"]
Readability Hard to parse visually Mirrors real-world hierarchy
Adding new interface Requires new key with prefix Just add a new inner dictionary
Updating all interfaces Must loop and filter by prefix Directly iterate over inner dict
Error-prone? Easy to mis-type long keys Clearer path, but must ensure parent keys exist

âś… Best Practices for Engineers

  • Always use .get() for safe access when you're not sure a key exists—this prevents your script from crashing on unexpected data.
  • Build nested dictionaries step by step rather than all at once—it's easier to debug and verify each level.
  • Use meaningful key names like "interfaces", "vlan", "status"—avoid abbreviations that might confuse you later.
  • Consider using a small helper function to safely drill into nested dictionaries: for example, a function that takes a list of keys and returns the value or a default.
  • When iterating, unpack wisely—use descriptive variable names like device_name, interface_name, interface_props so the code reads like English.

🚀 Next Steps

Now that you understand nested dictionaries, try extending this example: - Add a second device (e.g., "switch-02") with its own interfaces - Write logic to find all interfaces that are "down" across all devices - Create a function that takes a device name and returns a list of all IP addresses configured on that device

Nested dictionaries are the foundation for working with JSON data from network devices, APIs, and configuration files. Master this pattern, and you'll be ready to automate real network tasks with confidence.


Nested dictionaries store device configurations where each device contains multiple configuration parameters as key-value pairs.


đź”§ Example 1: Basic nested dictionary for a single switch

This example creates a simple nested dictionary with one device and its configuration settings.

switch_config = {
    "hostname": "SW-01",
    "vlans": {
        "10": "Management",
        "20": "Data",
        "30": "Voice"
    },
    "interfaces": {
        "Gig0/1": "access",
        "Gig0/2": "trunk"
    }
}

print(switch_config["hostname"])
print(switch_config["vlans"]["10"])
print(switch_config["interfaces"]["Gig0/1"])

📤 Output: SW-01 Management access


đź”§ Example 2: Accessing nested values with multiple keys

This example shows how to retrieve specific configuration values from deeply nested dictionaries.

router_config = {
    "hostname": "RTR-01",
    "ospf": {
        "process_id": 100,
        "area": 0,
        "networks": {
            "192.168.1.0": "0.0.0.255",
            "10.0.0.0": "0.255.255.255"
        }
    }
}

print(router_config["ospf"]["process_id"])
print(router_config["ospf"]["networks"]["192.168.1.0"])

📤 Output: 100 0.0.0.255


đź”§ Example 3: Adding new nested configuration to a device

This example demonstrates how to add new configuration parameters to an existing nested dictionary.

firewall_config = {
    "hostname": "FW-01",
    "interfaces": {
        "eth0": "outside",
        "eth1": "inside"
    }
}

firewall_config["interfaces"]["eth2"] = "dmz"
firewall_config["nat_rules"] = {
    "rule_1": {
        "source": "10.0.0.0/24",
        "destination": "any",
        "action": "permit"
    }
}

print(firewall_config["interfaces"])
print(firewall_config["nat_rules"]["rule_1"]["action"])

📤 Output: {'eth0': 'outside', 'eth1': 'inside', 'eth2': 'dmz'} permit


đź”§ Example 4: Looping through nested device configurations

This example shows how to iterate over all devices and their nested configuration parameters.

network_devices = {
    "SW-01": {
        "type": "switch",
        "vlans": [10, 20, 30],
        "status": "online"
    },
    "RTR-01": {
        "type": "router",
        "vlans": [10, 20],
        "status": "online"
    },
    "FW-01": {
        "type": "firewall",
        "vlans": [10],
        "status": "offline"
    }
}

for device_name, device_info in network_devices.items():
    print(f"Device: {device_name}")
    print(f"  Type: {device_info['type']}")
    print(f"  Status: {device_info['status']}")
    print(f"  VLANs: {device_info['vlans']}")

📤 Output: Device: SW-01 Type: switch Status: online VLANs: [10, 20, 30] Device: RTR-01 Type: router Status: online VLANs: [10, 20] Device: FW-01 Type: firewall Status: offline VLANs: [10]


đź”§ Example 5: Updating nested values across multiple devices

This example demonstrates how to modify nested configuration values for multiple devices at once.

device_configs = {
    "SW-01": {
        "hostname": "SW-01",
        "mgmt_ip": "192.168.1.10",
        "snmp": {
            "community": "public",
            "version": "v2c"
        }
    },
    "SW-02": {
        "hostname": "SW-02",
        "mgmt_ip": "192.168.1.11",
        "snmp": {
            "community": "public",
            "version": "v2c"
        }
    }
}

for device, config in device_configs.items():
    config["snmp"]["community"] = "secure_community"
    config["snmp"]["version"] = "v3"

print(device_configs["SW-01"]["snmp"])
print(device_configs["SW-02"]["snmp"])

📤 Output: {'community': 'secure_community', 'version': 'v3'} {'community': 'secure_community', 'version': 'v3'}


📊 Comparison Table

Operation Example Key Feature
Access nested value config["vlans"]["10"] Uses multiple keys
Add nested value config["interfaces"]["eth2"] = "dmz" Creates new key-value pair
Loop through devices for name, info in devices.items() Iterates all nested data
Update nested value config["snmp"]["community"] = "new" Modifies existing nested key
Check device status if device_info["status"] == "online" Conditional nested access

đź§­ Context Introduction

As you begin working with network automation, you'll quickly discover that real-world device configurations are rarely flat and simple. A single switch or router contains multiple interfaces, each with its own IP address, VLAN assignment, and status. This hierarchical data is best represented using nested dictionaries—dictionaries inside other dictionaries. In this guide, we'll walk through a practical example of modeling a network device's configuration using nested dictionaries, then show how to access, update, and iterate over that data.


⚙️ Why Nested Dictionaries for Network Configs?

  • Real-world structure: A device has interfaces; each interface has properties (IP, VLAN, status). This is a natural parent-child relationship.
  • Efficient lookups: Instead of looping through flat lists, you can access specific interface details directly by key.
  • Easy to update: Need to change the IP on interface GigabitEthernet0/1? You can do it in one line without touching other data.
  • Readable and maintainable: Nested dictionaries mirror how engineers think about device configurations—organized by device, then interface, then property.

🛠️ Building a Nested Device Config

Let's model a single network switch with two interfaces. We'll create a dictionary where the top-level key is the device hostname, and the value is another dictionary containing interface names as keys, each pointing to a dictionary of properties.

Example structure (conceptual): - Top-level key: "switch-01" - Inside that, a key "interfaces" with value being another dictionary - Inside interfaces, keys like "GigabitEthernet0/1" and "GigabitEthernet0/2" - Each interface has keys: "ip_address", "vlan", "status"

How to build it in Python: - Start with an empty dictionary: device_config = {} - Add the device name as a key with an empty dictionary as value: device_config["switch-01"] = {} - Inside that, add an "interfaces" key with another empty dictionary: device_config["switch-01"]["interfaces"] = {} - Now add each interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"] = {"ip_address": "10.0.1.1", "vlan": 10, "status": "up"} - Repeat for the second interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/2"] = {"ip_address": "10.0.2.1", "vlan": 20, "status": "down"}

The final structure looks like this (written as a single assignment for clarity): - device_config = {"switch-01": {"interfaces": {"GigabitEthernet0/1": {"ip_address": "10.0.1.1", "vlan": 10, "status": "up"}, "GigabitEthernet0/2": {"ip_address": "10.0.2.1", "vlan": 20, "status": "down"}}}}


🕵️ Accessing Nested Data

To retrieve specific values, chain the keys in order from outer to inner.

Examples of accessing data: - Get the IP address of the first interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"]["ip_address"] → returns "10.0.1.1" - Get the VLAN of the second interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/2"]["vlan"] → returns 20 - Get the entire dictionary for the first interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"] → returns {"ip_address": "10.0.1.1", "vlan": 10, "status": "up"}

What happens if a key doesn't exist? - Python raises a KeyError. To avoid this, use the .get() method: device_config.get("switch-01", {}).get("interfaces", {}).get("GigabitEthernet0/3", "Not found") → returns "Not found" instead of crashing.


📊 Updating Nested Values

Updating a value in a nested dictionary is straightforward—just assign a new value to the full key path.

Examples of updates: - Change the IP address on GigabitEthernet0/1: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"]["ip_address"] = "10.0.1.100" - Change the status of GigabitEthernet0/2 to "up": device_config["switch-01"]["interfaces"]["GigabitEthernet0/2"]["status"] = "up" - Add a new property (e.g., description) to an interface: device_config["switch-01"]["interfaces"]["GigabitEthernet0/1"]["description"] = "Uplink to core"

Adding a new interface entirely: - device_config["switch-01"]["interfaces"]["GigabitEthernet0/3"] = {"ip_address": "10.0.3.1", "vlan": 30, "status": "admin down"}


🔄 Iterating Over Nested Data

To process all interfaces on a device, you'll need nested loops—one for devices, one for interfaces.

How to loop through all interfaces: - Outer loop: for device_name, device_data in device_config.items(): — this gives you each device name and its data dictionary - Inner loop: for interface_name, interface_props in device_data["interfaces"].items(): — this gives you each interface name and its properties dictionary - Inside the inner loop, you can access individual properties: interface_props["ip_address"], interface_props["vlan"], interface_props["status"]

Practical output example (not code, just the logic): - For each device, print the device name - For each interface on that device, print the interface name, its IP, VLAN, and status - This lets you generate a report of all interfaces across all devices in one go


đź§© Comparison: Flat vs. Nested Structures

Feature Flat Dictionary Nested Dictionary
Example key "switch-01_Gig0/1_ip" ["switch-01"]["interfaces"]["Gig0/1"]["ip"]
Readability Hard to parse visually Mirrors real-world hierarchy
Adding new interface Requires new key with prefix Just add a new inner dictionary
Updating all interfaces Must loop and filter by prefix Directly iterate over inner dict
Error-prone? Easy to mis-type long keys Clearer path, but must ensure parent keys exist

âś… Best Practices for Engineers

  • Always use .get() for safe access when you're not sure a key exists—this prevents your script from crashing on unexpected data.
  • Build nested dictionaries step by step rather than all at once—it's easier to debug and verify each level.
  • Use meaningful key names like "interfaces", "vlan", "status"—avoid abbreviations that might confuse you later.
  • Consider using a small helper function to safely drill into nested dictionaries: for example, a function that takes a list of keys and returns the value or a default.
  • When iterating, unpack wisely—use descriptive variable names like device_name, interface_name, interface_props so the code reads like English.

🚀 Next Steps

Now that you understand nested dictionaries, try extending this example: - Add a second device (e.g., "switch-02") with its own interfaces - Write logic to find all interfaces that are "down" across all devices - Create a function that takes a device name and returns a list of all IP addresses configured on that device

Nested dictionaries are the foundation for working with JSON data from network devices, APIs, and configuration files. Master this pattern, and you'll be ready to automate real network tasks with confidence.

Interactive Views

You are currently in 📚 All-in-One mode. Use the tabs at the top to switch to 📖 Theory Only or 💻 Code Only views.

Nested dictionaries store device configurations where each device contains multiple configuration parameters as key-value pairs.


đź”§ Example 1: Basic nested dictionary for a single switch

This example creates a simple nested dictionary with one device and its configuration settings.

switch_config = {
    "hostname": "SW-01",
    "vlans": {
        "10": "Management",
        "20": "Data",
        "30": "Voice"
    },
    "interfaces": {
        "Gig0/1": "access",
        "Gig0/2": "trunk"
    }
}

print(switch_config["hostname"])
print(switch_config["vlans"]["10"])
print(switch_config["interfaces"]["Gig0/1"])

📤 Output: SW-01 Management access


đź”§ Example 2: Accessing nested values with multiple keys

This example shows how to retrieve specific configuration values from deeply nested dictionaries.

router_config = {
    "hostname": "RTR-01",
    "ospf": {
        "process_id": 100,
        "area": 0,
        "networks": {
            "192.168.1.0": "0.0.0.255",
            "10.0.0.0": "0.255.255.255"
        }
    }
}

print(router_config["ospf"]["process_id"])
print(router_config["ospf"]["networks"]["192.168.1.0"])

📤 Output: 100 0.0.0.255


đź”§ Example 3: Adding new nested configuration to a device

This example demonstrates how to add new configuration parameters to an existing nested dictionary.

firewall_config = {
    "hostname": "FW-01",
    "interfaces": {
        "eth0": "outside",
        "eth1": "inside"
    }
}

firewall_config["interfaces"]["eth2"] = "dmz"
firewall_config["nat_rules"] = {
    "rule_1": {
        "source": "10.0.0.0/24",
        "destination": "any",
        "action": "permit"
    }
}

print(firewall_config["interfaces"])
print(firewall_config["nat_rules"]["rule_1"]["action"])

📤 Output: {'eth0': 'outside', 'eth1': 'inside', 'eth2': 'dmz'} permit


đź”§ Example 4: Looping through nested device configurations

This example shows how to iterate over all devices and their nested configuration parameters.

network_devices = {
    "SW-01": {
        "type": "switch",
        "vlans": [10, 20, 30],
        "status": "online"
    },
    "RTR-01": {
        "type": "router",
        "vlans": [10, 20],
        "status": "online"
    },
    "FW-01": {
        "type": "firewall",
        "vlans": [10],
        "status": "offline"
    }
}

for device_name, device_info in network_devices.items():
    print(f"Device: {device_name}")
    print(f"  Type: {device_info['type']}")
    print(f"  Status: {device_info['status']}")
    print(f"  VLANs: {device_info['vlans']}")

📤 Output: Device: SW-01 Type: switch Status: online VLANs: [10, 20, 30] Device: RTR-01 Type: router Status: online VLANs: [10, 20] Device: FW-01 Type: firewall Status: offline VLANs: [10]


đź”§ Example 5: Updating nested values across multiple devices

This example demonstrates how to modify nested configuration values for multiple devices at once.

device_configs = {
    "SW-01": {
        "hostname": "SW-01",
        "mgmt_ip": "192.168.1.10",
        "snmp": {
            "community": "public",
            "version": "v2c"
        }
    },
    "SW-02": {
        "hostname": "SW-02",
        "mgmt_ip": "192.168.1.11",
        "snmp": {
            "community": "public",
            "version": "v2c"
        }
    }
}

for device, config in device_configs.items():
    config["snmp"]["community"] = "secure_community"
    config["snmp"]["version"] = "v3"

print(device_configs["SW-01"]["snmp"])
print(device_configs["SW-02"]["snmp"])

📤 Output: {'community': 'secure_community', 'version': 'v3'} {'community': 'secure_community', 'version': 'v3'}


📊 Comparison Table

Operation Example Key Feature
Access nested value config["vlans"]["10"] Uses multiple keys
Add nested value config["interfaces"]["eth2"] = "dmz" Creates new key-value pair
Loop through devices for name, info in devices.items() Iterates all nested data
Update nested value config["snmp"]["community"] = "new" Modifies existing nested key
Check device status if device_info["status"] == "online" Conditional nested access