[pypy-commit] pypy default: Add a __contains__ method on dict.viewkeys() and dict.viewitems().

arigo pypy.commits at gmail.com
Mon Feb 20 04:44:08 EST 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r90219:d9ee4fe1cd44
Date: 2017-02-20 10:43 +0100
http://bitbucket.org/pypy/pypy/changeset/d9ee4fe1cd44/

Log:	Add a __contains__ method on dict.viewkeys() and dict.viewitems().
	Without it, it would walk the list, which is the wrong complexity

diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -1585,9 +1585,25 @@
     def descr_iter(self, space):
         return W_DictMultiIterItemsObject(space, self.w_dict.iteritems())
 
+    def descr_contains(self, space, w_item):
+        if not space.isinstance_w(w_item, space.w_tuple):
+            return space.w_False
+        try:
+            w_key, w_value = space.fixedview_unroll(w_item, 2)
+            w_found = self.w_dict.getitem(w_key)
+        except OperationError as e:
+            if e.async(space):
+                raise
+            w_found = None
+        if w_found is None:
+            return space.w_False
+        return space.eq(w_value, w_found)
+
 class W_DictViewKeysObject(W_DictViewObject, SetLikeDictView):
     def descr_iter(self, space):
         return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys())
+    def descr_contains(self, space, w_key):
+        return self.w_dict.descr_contains(space, w_key)
 
 class W_DictViewValuesObject(W_DictViewObject):
     def descr_iter(self, space):
@@ -1598,6 +1614,7 @@
     __repr__ = interp2app(W_DictViewItemsObject.descr_repr),
     __len__ = interp2app(W_DictViewItemsObject.descr_len),
     __iter__ = interp2app(W_DictViewItemsObject.descr_iter),
+    __contains__ = interp2app(W_DictViewItemsObject.descr_contains),
 
     __eq__ = interp2app(W_DictViewItemsObject.descr_eq),
     __ne__ = interp2app(W_DictViewItemsObject.descr_ne),
@@ -1621,6 +1638,7 @@
     __repr__ = interp2app(W_DictViewKeysObject.descr_repr),
     __len__ = interp2app(W_DictViewKeysObject.descr_len),
     __iter__ = interp2app(W_DictViewKeysObject.descr_iter),
+    __contains__ = interp2app(W_DictViewKeysObject.descr_contains),
 
     __eq__ = interp2app(W_DictViewKeysObject.descr_eq),
     __ne__ = interp2app(W_DictViewKeysObject.descr_ne),
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -806,6 +806,8 @@
         assert "a" in keys
         assert 10 not in keys
         assert "Z" not in keys
+        raises(TypeError, "[] in keys")     # [] is unhashable
+        raises(TypeError, keys.__contains__, [])
         assert d.viewkeys() == d.viewkeys()
         e = {1: 11, "a": "def"}
         assert d.viewkeys() == e.viewkeys()
@@ -831,6 +833,8 @@
         assert () not in items
         assert (1,) not in items
         assert (1, 2, 3) not in items
+        assert ([], []) not in items     # [] is unhashable, but no TypeError
+        assert not items.__contains__(([], []))
         assert d.viewitems() == d.viewitems()
         e = d.copy()
         assert d.viewitems() == e.viewitems()


More information about the pypy-commit mailing list