Answer
In NetworkX 2.0 and later G.nodes() and G.edges() return NodeView and EdgeView objects instead of static lists. The view behaves like a set: it supports iteration, membership tests, and len(), but it does not support indexing, slicing, or list‑specific methods such as pop or insert. To keep legacy code working without a global shim, you should wrap only the calls that actually need list semantics.
Identifying the Calls that Require a List
- Search for list‑specific operations: grep the code base for
G.nodes()[, G.edges()[, G.nodes().pop, G.edges().insert, list(G.nodes()) etc. These are the spots that will break.
- Check for serialization or persistence: If the result of
G.nodes() is pickled, written to JSON, or sent over a network, it must be converted to a concrete list or tuple.
- Examine third‑party libraries: Some utilities (e.g.,
networkx.algorithms.community) may accept a view, but older plugins may not.
Once a location is flagged, replace the call with list(G.nodes()) or list(G.edges()). For large graphs, this costs a one‑time copy of the nodes/edges, but the copy is only as large as the slice you actually need. If you only need the first few items, consider using itertools.islice(G.nodes(), n) to avoid a full list build.
Trade‑offs Between Selective Wrappers and a Global Shim
- Selective wrappers: Minimal memory overhead, only the problematic paths incur the copy cost, and the rest of the code benefits from the lightweight view.
- Global shim (e.g., monkey‑patching
Graph.nodes to return a list): Simplifies the code base but forces every call to copy the entire node set each time, which can be expensive for very large graphs. It also hides the view’s dynamic nature, making debugging harder.
Is There a Configuration to Revert to Legacy Lists?
No, NetworkX does not provide a runtime flag or graph‑specific setting to switch nodes() or edges() back to lists. The API change is baked into the class definitions. The only supported way to obtain a list is to explicitly call list() on the view. If you need a persistent list for an entire session, create it once and reuse it, e.g.:
nodes_list = list(G.nodes())
# use nodes_list everywhere
Practical Verification Steps
- Run
import networkx as nx; G = nx.Graph(); print(type(G.nodes())) – you should see <class 'networkx.classes.view.NodeView'>.
- Modify the graph after retrieving the view:
G.add_node(1); print(1 in G.nodes()) – the view reflects the change.
- If a list is required, convert once:
nodes = list(G.nodes()); print(nodes[0]).
By following these steps, you can localise the necessary list conversions, avoid unnecessary copying, and maintain performance for the rest of your application.