diff options
-rw-r--r-- | Doc/library/stdtypes.rst | 5 | ||||
-rw-r--r-- | Lib/test/test_dictviews.py | 35 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Objects/dictobject.c | 58 |
4 files changed, 101 insertions, 0 deletions
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index a92d7b9..a732fb2 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2216,6 +2216,11 @@ available ("other" refers either to another view or a set): Return the symmetric difference (all elements either in *dictview* or *other*, but not in both) of the dictview and the other object as a new set. +.. method:: dictview.isdisjoint(other) + + Return True if the view has no elements in common with *other*. Sets are + disjoint if and only if their intersection is the empty set. + An example of dictionary view usage:: diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py index 277e05b..4c04079 100644 --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -112,6 +112,24 @@ class DictSetTest(unittest.TestCase): self.assertEqual(d1.keys() ^ set(d3.keys()), {'a', 'b', 'd', 'e'}) + self.assertFalse(d1.keys().isdisjoint(d1.keys())) + self.assertFalse(d1.keys().isdisjoint(d2.keys())) + self.assertFalse(d1.keys().isdisjoint(list(d2.keys()))) + self.assertFalse(d1.keys().isdisjoint(set(d2.keys()))) + self.assertTrue(d1.keys().isdisjoint({'x', 'y', 'z'})) + self.assertTrue(d1.keys().isdisjoint(['x', 'y', 'z'])) + self.assertTrue(d1.keys().isdisjoint(set(['x', 'y', 'z']))) + self.assertTrue(d1.keys().isdisjoint(set(['x', 'y']))) + self.assertTrue(d1.keys().isdisjoint(['x', 'y'])) + self.assertTrue(d1.keys().isdisjoint({})) + self.assertTrue(d1.keys().isdisjoint(d3.keys())) + + de = {} + self.assertTrue(de.keys().isdisjoint(set())) + self.assertTrue(de.keys().isdisjoint([])) + self.assertTrue(de.keys().isdisjoint(de.keys())) + self.assertTrue(de.keys().isdisjoint([1])) + def test_items_set_operations(self): d1 = {'a': 1, 'b': 2} d2 = {'a': 2, 'b': 2} @@ -144,6 +162,23 @@ class DictSetTest(unittest.TestCase): self.assertEqual(d1.items() ^ d3.items(), {('a', 1), ('b', 2), ('d', 4), ('e', 5)}) + self.assertFalse(d1.items().isdisjoint(d1.items())) + self.assertFalse(d1.items().isdisjoint(d2.items())) + self.assertFalse(d1.items().isdisjoint(list(d2.items()))) + self.assertFalse(d1.items().isdisjoint(set(d2.items()))) + self.assertTrue(d1.items().isdisjoint({'x', 'y', 'z'})) + self.assertTrue(d1.items().isdisjoint(['x', 'y', 'z'])) + self.assertTrue(d1.items().isdisjoint(set(['x', 'y', 'z']))) + self.assertTrue(d1.items().isdisjoint(set(['x', 'y']))) + self.assertTrue(d1.items().isdisjoint({})) + self.assertTrue(d1.items().isdisjoint(d3.items())) + + de = {} + self.assertTrue(de.items().isdisjoint(set())) + self.assertTrue(de.items().isdisjoint([])) + self.assertTrue(de.items().isdisjoint(de.items())) + self.assertTrue(de.items().isdisjoint([1])) + def test_main(): support.run_unittest(DictSetTest) @@ -12,6 +12,9 @@ What's New in Python 3.2 Alpha 2? Core and Builtins ----------------- +- Issue #9212: dict_keys and dict_items now provide the isdisjoint() + method, to conform to the Set ABC. + - Issue #9737: Fix a crash when trying to delete a slice or an item from a memoryview object. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 745e2dc..241790c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2807,7 +2807,63 @@ static PyNumberMethods dictviews_as_number = { (binaryfunc)dictviews_or, /*nb_or*/ }; +static PyObject* +dictviews_isdisjoint(PyObject *self, PyObject *other) +{ + PyObject *it; + PyObject *item = NULL; + + if (self == other) { + if (dictview_len((dictviewobject *)self) == 0) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + } + + /* Iterate over the shorter object (only if other is a set, + * because PySequence_Contains may be expensive otherwise): */ + if (PyAnySet_Check(other) || PyDictViewSet_Check(other)) { + Py_ssize_t len_self = dictview_len((dictviewobject *)self); + Py_ssize_t len_other = PyObject_Size(other); + if (len_other == -1) + return NULL; + + if ((len_other > len_self)) { + PyObject *tmp = other; + other = self; + self = tmp; + } + } + + it = PyObject_GetIter(other); + if (it == NULL) + return NULL; + + while ((item = PyIter_Next(it)) != NULL) { + int contains = PySequence_Contains(self, item); + Py_DECREF(item); + if (contains == -1) { + Py_DECREF(it); + return NULL; + } + + if (contains) { + Py_DECREF(it); + Py_RETURN_FALSE; + } + } + Py_DECREF(it); + if (PyErr_Occurred()) + return NULL; /* PyIter_Next raised an exception. */ + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(isdisjoint_doc, +"Return True if the view and the given iterable have a null intersection."); + static PyMethodDef dictkeys_methods[] = { + {"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O, + isdisjoint_doc}, {NULL, NULL} /* sentinel */ }; @@ -2892,6 +2948,8 @@ static PySequenceMethods dictitems_as_sequence = { }; static PyMethodDef dictitems_methods[] = { + {"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O, + isdisjoint_doc}, {NULL, NULL} /* sentinel */ }; |