Python
Graph Modeling
Data Structures
Programming
Python Libraries

Modeling a graph in Python

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Modeling a graph in Python starts with a simple question: what operations matter most for your problem. If you care about fast adjacency lookups and algorithm control, a custom adjacency list is often enough. If you care about graph algorithms, analysis, and rich metadata, a library such as NetworkX is usually the better choice.

Use an Adjacency List for Most Custom Code

An adjacency list is the most common graph representation in Python. It maps each node to the nodes it connects to.

python
1graph = {
2    "A": ["B", "C"],
3    "B": ["C"],
4    "C": ["A"],
5    "D": []
6}
7
8print(graph["A"])

This is compact, easy to inspect, and efficient for traversal algorithms such as BFS and DFS.

Add Weights When the Problem Needs Them

If edges carry costs or distances, represent adjacency with weight information instead of plain neighbor lists.

python
1weighted_graph = {
2    "A": [("B", 5), ("C", 2)],
3    "B": [("C", 1)],
4    "C": [("A", 4)],
5}
6
7for neighbor, weight in weighted_graph["A"]:
8    print(neighbor, weight)

This keeps the structure explicit without forcing a heavier abstraction too early.

Wrap the Representation in a Class When Mutations Matter

For larger programs, a graph class makes repeated node and edge operations easier to manage.

python
1class Graph:
2    def __init__(self):
3        self.adj = {}
4
5    def add_node(self, node):
6        self.adj.setdefault(node, [])
7
8    def add_edge(self, src, dst):
9        self.add_node(src)
10        self.add_node(dst)
11        self.adj[src].append(dst)
12
13g = Graph()
14g.add_edge("A", "B")
15g.add_edge("A", "C")
16print(g.adj)

This is often a good compromise between raw dictionaries and a full graph library.

Use NetworkX When You Need More Than Storage

If the task involves shortest paths, centrality, connected components, or graph export, NetworkX saves a lot of time.

python
1import networkx as nx
2
3G = nx.DiGraph()
4G.add_edge("A", "B")
5G.add_edge("A", "C")
6
7print(list(G.successors("A")))
8print(nx.shortest_path(G, "A", "C"))

The benefit is not only storage. It is the ecosystem of algorithms and utilities that comes with it.

Pick Node and Edge Representations That Fit the Domain

Python graph models work best when node identity is stable and hashable. Strings, integers, and tuples are common because they make dictionary-based adjacency structures simple.

For edges, store only the metadata you will actually use. If weights, labels, or timestamps matter, include them explicitly rather than bolting them on later in inconsistent formats. Clean graph modeling starts with a clean definition of node identity and edge payload.

Choose Directed or Undirected Deliberately

Do not treat direction as an afterthought. A social friendship graph and a task-dependency graph may both look like "connections", but their semantics are different. In code, that affects whether you store one edge or two.

For an undirected graph with adjacency lists, add both directions:

python
def add_undirected_edge(graph, a, b):
    graph.setdefault(a, []).append(b)
    graph.setdefault(b, []).append(a)

Being explicit here avoids subtle traversal bugs later.

Common Pitfalls

  • Choosing a graph library before knowing whether you only need simple adjacency storage.
  • Forgetting to model edge direction when the problem depends on it.
  • Mixing weighted and unweighted edges in the same structure without a clear rule.
  • Using dense matrix-style thinking when the graph is sparse and adjacency lists are simpler.
  • Rebuilding common graph algorithms manually when a mature library already solves them well.

Graph models age badly when node identity rules are fuzzy. Decide that rule early.

Summary

  • In Python, adjacency lists are the usual starting point for graph modeling.
  • Weighted graphs need explicit edge payloads such as cost tuples.
  • A small graph class helps when the graph is mutated in many places.
  • NetworkX is usually the right choice when algorithms and analysis matter more than raw storage.
  • Choose node identity and edge metadata deliberately before the graph starts growing.

Course illustration
Course illustration

All Rights Reserved.