Repository: networkx/networkx

Issue:
Can't retrieve all edges for pair of nodes in Multi(Di)Graph
<!--- Provide a general summary of the issue in the Title above -->
According to the docs, I should be able to subscript into Multi(Di)Graph by pair of nodes and retrieve all the edges:

> Hence, **G.edges[u, v]['color']** provides the value of the color attribute for edge (u, v) while for (u, v, c) in G.edges(data='color', default='red'): iterates through all the edges yielding the color attribute. [Docs](https://networkx.org/documentation/stable/reference/classes/generated/networkx.MultiGraph.edges.html)

Either the docs are incorrect (I suspect a copy-paste from non-Multi Graph/DiGraph), or this does not work as expected.

### Current Behavior
<!--- Tell us what happens instead of the expected behavior -->
```python
G = nx.MultiGraph()  # or MultiDiGraph
nx.add_path(G, [0, 1, 2])
key = G.add_edge(1, 2, weight=5)
G.edges[1, 2]
# G.edges[1, 2, 0] or G.edges[1, 2, 1] works
```

> ValueError: not enough values to unpack (expected 3, got 2)

### Expected Behavior
<!--- Tell us what should happen -->

I would expect to be able to retrieve all the (multi-)edges for a pair of nodes by subscripting into the edges of the MultiGraph:
```python
G.edges[1, 2]
```

> MultiEdgeView([(1, 2, 0), (1, 2, 1)])

### Environment
<!--- Please provide details about your local environment -->
Python version: 3.8
NetworkX version: 2.6.1



Discussion:
> I should be able to subscript into Multi(Di)Graph by pair of nodes and retrieve all the edges

The docs aren't particularly clear here, though I don't think they support the interpretation that indexing edges by node numbers will return all edges between the two nodes --- rather, indexing EdgeView (and subclasses) is intended to access specific edges (or their attributes). In the case of MultiGraphs, each edge includes a key hence the above error. I agree that the documentation could be improved here to make this more clear.
Ye, I wanted a quick way to get a list of a specific attribute value for each of the edges. I ended up doing this, is there a better way?

```
G = nx.MultiGraph()
G.add_edge(1, 2, weight=3)
G.add_edge(1, 2, weight=5)
list(map(itemgetter('weight'), G[1][2].values()))
```
> Out[10]: [3, 5]

I was missing that `G[1][2]` provides an `AtlasView` of all the edges with attributes.
> a quick way to get a list of a specific attribute value for each of the edges. I ended up doing this, is there a better way?

It depends on what you want specifically. For example, what you've done above will grab the `"weight"` attribute for every edge between two nodes (only relevant for multigraphs). Your solution is perfectly fine, though I would probably use list comprehension instead of the `list(map(` pattern:

```python
>>> e12_wts = [e['weight'] for e in G[1][2].values()]
```

If instead you wanted the attribute for *all* edges (instead of all edges between two specific nodes) then you'd iterate over the edge view (with data), something like:

```python
>>> G.add_edge(0,1, weight=7)  # Add a new edge for illustration
>>> edge_wts = [d["weight"] for _, _, d in G.edges(data=True)]
```
Still dusting off my python hat, list comprehension is much more legible xD thanks for the help!
The DataView can also specify which data attribute (instead of `data=True`):
```python
>>> G.add_edge(0,1, weight=7)  # Add a new edge for illustration
>>> edge_wts = [wt for _, _, wt in G.edges(data="weight")]
```
You can specify a `default` value for edges that don't have that attribute (the default edge weight default is `None`).  For `MultiGraph` You can also request that the edge keys be returned -- then you get a 4-tuple.
```python
>>> edge_wts = [wt for _, _, wt in G.edges(data="weight", default=1)]
```

But the bottom line is that the docs for Multi(Di)Graph need to be updated...   :}

Resolving patch:
diff --git a/networkx/classes/multidigraph.py b/networkx/classes/multidigraph.py
--- a/networkx/classes/multidigraph.py
+++ b/networkx/classes/multidigraph.py
@@ -569,14 +569,14 @@ def edges(self):
         as well as edge attribute lookup. When called, it also provides
         an EdgeDataView object which allows control of access to edge
         attributes (but does not provide set-like operations).
-        Hence, `G.edges[u, v, k]['color']` provides the value of the color
-        attribute for edge from `u` to `v` with key `k` while
-        `for (u, v, k, c) in G.edges(data='color', default='red',
-        keys=True):` iterates through all the edges yielding the color
-        attribute with default `'red'` if no color attribute exists.
+        Hence, ``G.edges[u, v, k]['color']`` provides the value of the color
+        attribute for the edge from ``u`` to ``v`` with key ``k`` while
+        ``for (u, v, k, c) in G.edges(data='color', default='red', keys=True):``
+        iterates through all the edges yielding the color attribute with
+        default `'red'` if no color attribute exists.
 
         Edges are returned as tuples with optional data and keys
-        in the order (node, neighbor, key, data). If `keys=True` is not
+        in the order (node, neighbor, key, data). If ``keys=True`` is not
         provided, the tuples will just be (node, neighbor, data), but
         multiple tuples with the same node and neighbor will be
         generated when multiple edges between two nodes exist.
@@ -599,10 +599,10 @@ def edges(self):
 
         Returns
         -------
-        edges : EdgeView
+        edges : OutMultiEdgeView
             A view of edge attributes, usually it iterates over (u, v)
             (u, v, k) or (u, v, k, d) tuples of edges, but can also be
-            used for attribute lookup as `edges[u, v, k]['foo']`.
+            used for attribute lookup as ``edges[u, v, k]['foo']``.
 
         Notes
         -----
diff --git a/networkx/classes/multigraph.py b/networkx/classes/multigraph.py
--- a/networkx/classes/multigraph.py
+++ b/networkx/classes/multigraph.py
@@ -763,17 +763,21 @@ def edges(self):
 
         edges(self, nbunch=None, data=False, keys=False, default=None)
 
-        The EdgeView provides set-like operations on the edge-tuples
+        The MultiEdgeView provides set-like operations on the edge-tuples
         as well as edge attribute lookup. When called, it also provides
         an EdgeDataView object which allows control of access to edge
         attributes (but does not provide set-like operations).
-        Hence, `G.edges[u, v, k]['color']` provides the value of the color
-        attribute for edge `(u, v, k)` while
-        `for (u, v, c) in G.edges(data='color', default='red'):`
-        iterates through all the edges yielding the color attribute.
+        Hence, ``G.edges[u, v, k]['color']`` provides the value of the color
+        attribute for the edge from ``u`` to ``v`` with key ``k`` while
+        ``for (u, v, k, c) in G.edges(data='color', keys=True, default="red"):``
+        iterates through all the edges yielding the color attribute with
+        default `'red'` if no color attribute exists.
 
         Edges are returned as tuples with optional data and keys
-        in the order (node, neighbor, key, data).
+        in the order (node, neighbor, key, data). If ``keys=True`` is not
+        provided, the tuples will just be (node, neighbor, data), but
+        multiple tuples with the same node and neighbor will be generated
+        when multiple edges exist between two nodes.
 
         Parameters
         ----------
@@ -795,7 +799,7 @@ def edges(self):
         edges : MultiEdgeView
             A view of edge attributes, usually it iterates over (u, v)
             (u, v, k) or (u, v, k, d) tuples of edges, but can also be
-            used for attribute lookup as `edges[u, v, k]['foo']`.
+            used for attribute lookup as ``edges[u, v, k]['foo']``.
 
         Notes
         -----
@@ -804,7 +808,7 @@ def edges(self):
 
         Examples
         --------
-        >>> G = nx.MultiGraph()  # or MultiDiGraph
+        >>> G = nx.MultiGraph()
         >>> nx.add_path(G, [0, 1, 2])
         >>> key = G.add_edge(2, 3, weight=5)
         >>> key2 = G.add_edge(2, 1, weight=2)  # multi-edge


Test patch: