]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #9212: Added the missing isdisjoint method to the dict_keys and
authorDaniel Stutzbach <daniel@stutzbachenterprises.com>
Thu, 2 Sep 2010 15:06:06 +0000 (15:06 +0000)
committerDaniel Stutzbach <daniel@stutzbachenterprises.com>
Thu, 2 Sep 2010 15:06:06 +0000 (15:06 +0000)
dict_items views.  The method is required by the collections.Set ABC,
which the views register as supporting.

Doc/library/stdtypes.rst
Lib/test/test_dictviews.py
Misc/NEWS
Objects/dictobject.c

index a92d7b9b61741cca198b999e0cdfe2afb5fdc175..a732fb29446abf5dbd8f627c33c975ccb50478c2 100644 (file)
@@ -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::
 
index 277e05b3679e783342b8c4b839f1e950645b6ea0..4c040796f5e2e192d96db4b603cc44feabea91bc 100644 (file)
@@ -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)
index 92d858a92df3b6c87992fbff8ebe74e522362759..97171e09443cbd66560326feb503df88b9ea1bde 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
 
index 745e2dc9fe8a832402ada216a3dfff133b56b2bf..241790ceba27d0212b05d73e3372198aa1dbe2a7 100644 (file)
@@ -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 */
 };