Repository: networkx/networkx

Issue:
len(G.edges) unexpected values
I'm not sure if this is a bug or expected behavior but it's at least confusing.  This is using 2.0 nx.Graph() - I would provide the data to recreate, but it's private and I'm not sure why this is occurring, which might just be my lack of knowledge
```
>>> len(G.edges())
300
>>> G.number_of_edges()
312
>>> count = 0
>>> s = set()
>>> for edge in G.edges():
...     seen = edge in s or (edge[1], edge[0]) in s
...     if not seen:
...         count += 1
...     s.add(edge)
>>> count
312
```
What would be likely reasons that len() would give a different answer than number_of_edges()?  I thought it was because of reversed edges, but that doesn't seem to be the case either.


Discussion:
This looks like a bug.  Thanks for the report!
I believe the cause is selfloops.  It looks like ```len(G.edges)``` does not count selfloops.

Short term fix is to use ```G.size()``` or ```G.number_of_edges()``` but tweak the following in more complex situations:

    sum(len(nbrs)+(n in nbrs) for n, nbrs in G.adj.items()) // 2

or

    sum(1 for e in G.edges)

I do have self loops in the data, so that is likely the case.  Thanks!

Resolving patch:
diff --git a/networkx/classes/reportviews.py b/networkx/classes/reportviews.py
--- a/networkx/classes/reportviews.py
+++ b/networkx/classes/reportviews.py
@@ -791,8 +791,7 @@ def __init__(self, viewer, nbunch=None,
                         if data in dd else (n, nbr, default)
 
     def __len__(self):
-        return sum(len(kd) for n, nbrs in self._nodes_nbrs()
-                   for nbr, kd in nbrs.items())
+        return sum(1 for e in self)
 
     def __iter__(self):
         return (self._report(n, nbr, k, dd) for n, nbrs in self._nodes_nbrs()
@@ -821,10 +820,6 @@ class MultiEdgeDataView(OutMultiEdgeDataView):
     """An EdgeDataView class for edges of MultiGraph; See EdgeDataView"""
     __slots__ = ()
 
-    def __len__(self):
-        # nbunch makes it hard to count edges between nodes in nbunch
-        return sum(1 for e in self)
-
     def __iter__(self):
         seen = {}
         for n, nbrs in self._nodes_nbrs():
@@ -1016,7 +1011,7 @@ class EdgeView(OutEdgeView):
     dataview = EdgeDataView
 
     def __len__(self):
-        return sum(len(nbrs) for n, nbrs in self._nodes_nbrs()) // 2
+        return sum(len(nbrs) + (n in nbrs) for n, nbrs in self._nodes_nbrs()) // 2
 
     def __iter__(self):
         seen = {}
@@ -1120,8 +1115,7 @@ class MultiEdgeView(OutMultiEdgeView):
     dataview = MultiEdgeDataView
 
     def __len__(self):
-        return sum(len(kdict) for n, nbrs in self._nodes_nbrs()
-                   for nbr, kdict in nbrs.items()) // 2
+        return sum(1 for e in self)
 
     def __iter__(self):
         seen = {}


Test patch:
diff --git a/networkx/classes/tests/test_reportviews.py b/networkx/classes/tests/test_reportviews.py
--- a/networkx/classes/tests/test_reportviews.py
+++ b/networkx/classes/tests/test_reportviews.py
@@ -326,6 +326,12 @@ def test_len(self):
         assert_equal(len(self.G.edges()), 8)
         assert_equal(len(self.G.edges), 8)
 
+        H = self.G.copy()
+        H.add_edge(1, 1)
+        assert_equal(len(H.edges(1)), 3)
+        assert_equal(len(H.edges()), 9)
+        assert_equal(len(H.edges), 9)
+
 
 class TestOutEdgeDataView(TestEdgeDataView):
     def setUp(self):
@@ -351,6 +357,12 @@ def test_len(self):
         assert_equal(len(self.G.edges()), 8)
         assert_equal(len(self.G.edges), 8)
 
+        H = self.G.copy()
+        H.add_edge(1, 1)
+        assert_equal(len(H.edges(1)), 2)
+        assert_equal(len(H.edges()), 9)
+        assert_equal(len(H.edges), 9)
+
 
 class TestInEdgeDataView(TestOutEdgeDataView):
     def setUp(self):
@@ -486,6 +498,12 @@ def test_len(self):
         num_ed = 9 if self.G.is_multigraph() else 8
         assert_equal(len(ev), num_ed)
 
+        H = self.G.copy()
+        H.add_edge(1, 1)
+        assert_equal(len(H.edges(1)), 3 + H.is_multigraph() - H.is_directed())
+        assert_equal(len(H.edges()), num_ed + 1)
+        assert_equal(len(H.edges), num_ed + 1)
+
     def test_and(self):
         # print("G & H edges:", gnv & hnv)
         ev = self.eview(self.G)