The Right Tool for the Right Job

As a network engineer embracing Python, you've likely used structures like lists, dictionaries, or maybe even tuples and sets, whether to parse API responses, manage configuration templates, or model device metadata. But with multiple options on the table, how do you choose the most appropriate data structure for each job?

Python offers several built-in collection types — List, Tuple, Set, Frozenset, and Dictionary — and while they may seem interchangeable at first glance, each has distinct properties that impact how your automation code behaves, scales, and communicates intent.

In this post, we won’t just describe the differences; we’ll show you how to think like an engineer when making a choice between them.

You’ll learn:

  • How each type behaves in terms of ordering, mutability, and uniqueness

  • When to use a list vs. a set, or a dictionary vs. a tuple

  • Some examples from network engineering and automation

  • How to avoid subtle bugs or inefficiencies just by choosing the right type

As always, we’ll provide annotated examples, decision-making criteria, and practical use cases, all rooted in scenarios you’ll actually face when working with network data.

And yes, you're encouraged to copy, modify, and run the code as you follow along. It’s the best way to internalize these concepts and start writing Python that speaks the language of networking.

Let’s dive in.

The Core Concepts

Before we compare use cases, let’s get grounded in three fundamental concepts that differentiate these collections:

  1. Ordering: Are the elements stored in a specific sequence?

  2. Mutability: Can you change the data after creation?

  3. Uniqueness: Does the collection allow duplicate values?

Here’s a quick summary:

Characteristic

List

Tuple

Set

Dictionary

Ordered

Yes

Yes

No

No (Python ≥3.7: Yes)

Mutable

Yes

No

Yes

Yes

Allows Duplicates

Yes

Yes

No

Keys must be unique

📌 Note: Python dictionaries preserve insertion order from version 3.7 onwards, but this is not the same as index-based access like lists or tuples.

A more comprehensive overview that emphasizes these main differences among the various data types:

When to Use Each Collection

Let’s now dig deeper into each, with network-specific use cases and selection criteria.

1. List

Use when you need ordered, changeable sequences with duplicate elements.

Best for:

  • Keeping a sequence of events or states in automation workflows

  • Maintaining a list of IP addresses, VLAN IDs, or MAC addresses

  • Creating task queues (e.g., devices to configure)

vlans = [10, 20, 30, 20]  # Duplicates are allowed
vlans.append(40)

Watch out for:

  • Lists consume more memory than tuples

  • Modifying them inside functions can create side effects

When lists compete with sets: prefer lists if order or duplicates matter.

2. Tuple

Use when you need an ordered, immutable group of elements, especially when values must not change, such as coordinates, constant settings, or version identifiers.

Best for:

  • Device location coordinates: ("rack42", "row7", "U13")

  • Representing fixed configuration versions: ("v1.2.3", "JunOS", "stable")

  • Function return values: return hostname, ip_address

interface_tuple = ("eth0", "up", "10.0.0.1")

Why it matters:

  • Tuples are faster and require less memory than lists

  • Immutability guarantees safety, which is critical in distributed or multithreaded scripts

When tuples compete with lists: choose tuples for safety and fixed-length data.

3. Set

Use when you want to store unique items and perform fast membership tests or set operations like union, intersection, or difference.

Best for:

  • Deduplicating a list of interface names or BGP neighbors

  • Comparing two device inventories: missing_devices = expected - actual

  • Membership checks: if "eth1" in active_ifaces

interfaces = {"eth0", "eth1", "eth2", "eth0"}  # 'eth0' appears only once

When we initialize a set in Python with duplicate elements, as in the example {"eth0", "eth1", "eth2", "eth0"}, the language automatically removes repetitions, keeping only unique values in the final set. This deduplication is not a separate operation, but rather part of the set creation process itself. The purpose of including "eth0" twice in the declaration above is precisely to demonstrate this behavior: even though the initialization contains duplicates, the resulting set will contain each element only once, highlighting its nature of storing exclusively unique items.

4. Frozenset

Use when you need an immutable version of a set, often for safe lookups or dictionary keys.

Best for:

  • Creating reliable, hashable sets to use as keys in dictionaries

  • Preventing changes to critical collections of allowed or blocked values

  • Safe role definitions: frozenset(["admin", "viewer", "editor"])

trusted_roles = frozenset(["network-admin", "sec-ops"])

When frozensets compete with sets: use frozensets when you need immutability, e.g., configuration profiles or permission groups that must not change.

5. Dictionary

Use when your data needs to be organized in key-value pairs and accessed non-sequentially, which is extremely common in network tasks.

Best for:

  • Storing interface metadata: {"eth0": {"status": "up", "ip": "10.1.1.1"}}

  • Representing device configs

  • Parsing structured JSON from APIs

device_info = {
    "hostname": "rtr-01",
    "interfaces": {"eth0": "up", "eth1": "down"},
    "location": "Dublin"
}

Why dictionaries win:

  • Keys are unique, access is fast, and structure is natural

  • They’re the most flexible Python collection, used heavily in automation, YAML, and JSON structures

When dictionaries compete with lists or tuples: choose dicts when each item has a meaningful label.

Tie-Breaking Criteria

Question to Ask

Collection to Favor

Do I care about order?

List or Tuple

Do I need to modify values?

List, Set, Dictionary

Do I need fixed values that shouldn't change?

Tuple, Frozenset

Do I want uniqueness (no duplicates)?

Set, Frozenset

Do I need key-value mappings?

Dictionary

Will I check membership frequently?

Set or Frozenset

Network Automation Scenario: Interface Metadata Lookup

Let’s say you want to process interface data returned from a network API.

interfaces = {
    "eth0": {"status": "up", "ip": "10.0.0.1"},
    "eth1": {"status": "down", "ip": "10.0.0.2"},
    "eth2": {"status": "up", "ip": "10.0.0.3"}
}

# You want a list of only "up" interfaces
up_ifaces = [iface for iface, meta in interfaces.items() if meta["status"] == "up"]
print(up_ifaces)

Why a dictionary here?

  • You’re mapping names to metadata

  • You want quick lookups, not index-based iteration

Why list the result?

  • You want an ordered, printable result

  • Duplicates wouldn’t be a problem, but you control them through logic

Assessment: Modeling Network State with Python Data Types

The Scenario

You’ve been tasked with building a lightweight local tool that helps your network team summarize interface telemetry data and device metadata collected from multiple routers. These routers are part of a hybrid IP/MPLS backbone across several core sites.

The telemetry snapshots are exported every 5 minutes by a streaming collector (mocked here as Python input data). Your script should help the engineer:

  • Normalize and filter this raw data

  • Summarize interface usage

  • Identify redundant or inconsistent records

  • Track immutable references such as region codes and static system identifiers

What We Want To Accomplish

  1. Store telemetry readings from each router interface.

  2. Ensure device metadata (hostname, location, region, vendor, version) is correctly modeled and protected from accidental changes.

  3. Remove duplicate IPs reported across interfaces.

  4. Validate if any interfaces are reported as down.

  5. Display a final structured summary combining all relevant information in an easy-to-read format.

What the Requirements Are

  • Use a list to store and iterate over interface readings from multiple routers.

  • Use a tuple to store immutable metadata (such as hostname, site code, and vendor).

  • Use a set to deduplicate IP addresses collected from interfaces.

  • Use a frozenset to represent a predefined set of approved region codes that must not be changed.

  • Use a dictionary to associate interfaces with their respective traffic statistics and statuses.

The Constraints

  • Region codes must be validated against a fixed set of known good values.

  • No interface should appear more than once in the IP summary (deduplication is essential).

  • Interface statuses must be reported accurately with minimal processing overhead.

  • The code must run without using external libraries; it should utilize only built-in Python types and logic.

  • The solution must work even if additional devices are added later.

The Expected Outcomes

At the end of the script execution:

  • Interfaces should be categorized and listed by status.

  • Redundant IPs should be removed.

  • Site and device metadata should remain untouched and be correctly mapped.

  • All data types should be used in a manner that supports clean logic and separation of concerns.

Your Turn

Write a Python script using the information above and your knowledge of Python collections. Design your data model wisely, and implement the logic to parse, store, analyze, and print out a structured summary of the network snapshot.

You can copy this to your IDE and start experimenting. Once you’re confident with your solution, compare it with the reference implementation below.

Reference Implementation & Step-by-Step Review

Don't rush to check the solution below! Give yourself a chance to try, see if you can write your code and see how it works! That's how you'll learn!

# Immutable metadata for a router
device_info = ("router-101", "DUB1", "Juniper", "MX204")  # Tuple

# Approved region codes (cannot change during execution)
approved_regions = frozenset(["EU-WEST", "US-EAST", "AP-SOUTH"])  # Frozenset

# Site metadata
site_metadata = {
    "hostname": device_info[0],
    "location": device_info[1],
    "vendor": device_info[2],
    "model": device_info[3],
    "region": "EU-WEST"
}  # Dictionary

# Validate the region code
if site_metadata["region"] not in approved_regions:
    print("❌ Region code not approved.")
    exit()

# List of interface reports
interface_readings = [
    {"name": "ge-0/0/0", "ip": "10.0.0.1", "status": "up", "usage": 52},
    {"name": "ge-0/0/1", "ip": "10.0.0.2", "status": "down", "usage": 0},
    {"name": "ge-0/0/2", "ip": "10.0.0.3", "status": "up", "usage": 71},
    {"name": "ge-0/0/3", "ip": "10.0.0.1", "status": "up", "usage": 55},  # duplicate IP
]  # List of dictionaries

# Deduplicate IPs using a set
ip_set = set()
for iface in interface_readings:
    ip_set.add(iface["ip"])
print("\n🔎 Unique IP addresses in use:", ip_set)

# Dictionary to associate interfaces with status and usage
interface_summary = {}
for iface in interface_readings:
    interface_summary[iface["name"]] = {
        "status": iface["status"],
        "usage_percent": iface["usage"]
    }

# Print down interfaces
down_links = [k for k, v in interface_summary.items() if v["status"] == "down"]
if down_links:
    print("\n⚠️  Down interfaces detected:")
    for intf in down_links:
        print(f" - {intf}")

# Final Summary
print("\n📦 Device Summary")
print(f"Device: {device_info[0]} located at {device_info[1]}")
print(f"Vendor: {device_info[2]} ({device_info[3]})")
print("Region:", site_metadata["region"])
print("Total Interfaces:", len(interface_summary))

# Optional: Print interface stats
print("\n📊 Interface Stats:")
for name, data in interface_summary.items():
    print(f" - {name}: {data['status'].upper()} at {data['usage_percent']}% usage")

What You Should Learn from This Exercise

  • Tuples are perfect for metadata that should never be overwritten.

  • Frozensets ensure the integrity of fixed lookup values like approved codes or supported vendors.

  • Lists work best when you have sequential items, such as telemetry reports.

  • Dictionaries allow fast key-value lookups and structured data modeling.

  • Sets are your go-to for deduplicating and performing efficient membership checks.

The exercise simulates what you’d face when working with streaming telemetry, API parsing, and device state reconciliation pipelines.

The more you automate, the more you’ll lean on these Python collections.

Knowing when to use each goes far beyond just the syntax: it will give you safety, performance, and clarity of your code. Your collections reflect your intent. Choose wisely, and you’ll write cleaner, more robust network automation code.

See you in the next chapter!

Leonardo Furtado

Keep Reading