This patch implements rich comparisons with dict views such that
dict().keys() can be compared like a set (i.e. < is subset, etc).
Keir
Index: Objects/dictobject.c
===================================================================
--- Objects/dictobject.c (revision 57367)
+++ Objects/dictobject.c (working copy)
@@ -2371,6 +2371,7 @@
# define PyDictViewSet_Check(obj) \
(PyDictKeys_Check(obj) || PyDictItems_Check(obj))
+/* Return 1 if self is a subset of other */
static int
all_contained_in(PyObject *self, PyObject *other)
{
@@ -2398,41 +2399,61 @@
static PyObject *
dictview_richcompare(PyObject *self, PyObject *other, int op)
{
+ Py_ssize_t len_self, len_other;
+ PyObject *result;
+
assert(self != NULL);
assert(PyDictViewSet_Check(self));
assert(other != NULL);
- if ((op == Py_EQ || op == Py_NE) &&
- (PyAnySet_Check(other) || PyDictViewSet_Check(other)))
- {
- Py_ssize_t len_self, len_other;
- int ok;
- PyObject *result;
- len_self = PyObject_Size(self);
- if (len_self < 0)
- return NULL;
- len_other = PyObject_Size(other);
- if (len_other < 0)
- return NULL;
- if (len_self != len_other)
- ok = 0;
- else if (len_self == 0)
- ok = 1;
- else
- ok = all_contained_in(self, other);
- if (ok < 0)
- return NULL;
- if (ok == (op == Py_EQ))
- result = Py_True;
- else
- result = Py_False;
- Py_INCREF(result);
- return result;
- }
- else {
+ if (!PyAnySet_Check(other) && !PyDictViewSet_Check(other)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
- }
+ }
+
+ len_self = PyObject_Size(self);
+ if (len_self < 0)
+ return NULL;
+ len_other = PyObject_Size(other);
+ if (len_other < 0)
+ return NULL;
+
+ result = Py_False;
+ switch(op) {
+ case Py_NE:
+ if (len_self != len_other ||
+ len_self == 0 ||
+ !all_contained_in(self, other))
+ result = Py_True;
+ break;
+ case Py_EQ:
+ if (len_self == len_other &&
+ (len_self == 0 || all_contained_in(self, other)))
+ result = Py_True;
+ break;
+ case Py_LT:
+ if (len_self < len_other &&
+ all_contained_in(self, other))
+ result = Py_True;
+ break;
+ case Py_LE:
+ if (len_self <= len_other &&
+ all_contained_in(self, other))
+ result = Py_True;
+ break;
+ case Py_GT:
+ if (len_self > len_other &&
+ all_contained_in(other, self))
+ result = Py_True;
+ break;
+ case Py_GE:
+ if (len_self >= len_other &&
+ all_contained_in(other, self))
+ result = Py_True;
+ break;
+ }
+ Py_INCREF(result);
+ return result;
}
/*** dict_keys ***/
Index: Lib/test/test_dict.py
===================================================================
--- Lib/test/test_dict.py (revision 57367)
+++ Lib/test/test_dict.py (working copy)
@@ -398,6 +398,42 @@
else:
self.fail("< didn't raise Exc")
+ def test_keys_contained(self):
+ # Test rich comparisons against dict key views, which should behave the
+ # same as sets.
+ empty = dict()
+ empty2 = dict()
+ smaller = {1:1, 2:2}
+ larger = {1:1, 2:2, 3:3}
+ larger2 = {1:1, 2:2, 3:3}
+ larger3 = {4:1, 2:2, 3:3}
+
+ self.assert_(smaller.keys() < larger.keys())
+ self.assert_(smaller.keys() <= larger.keys())
+ self.assert_(larger.keys() > smaller.keys())
+ self.assert_(larger.keys() >= smaller.keys())
+
+ self.assertFalse(smaller.keys() >= larger.keys())
+ self.assertFalse(smaller.keys() > larger.keys())
+ self.assertFalse(larger.keys() <= smaller.keys())
+ self.assertFalse(larger.keys() < smaller.keys())
+
+ # Inequality strictness
+ self.assertTrue(larger2.keys() >= larger.keys())
+ self.assertTrue(larger2.keys() <= larger.keys())
+ self.assertFalse(larger2.keys() > larger.keys())
+ self.assertFalse(larger2.keys() < larger.keys())
+
+ self.assertEquals(larger.keys(), larger2.keys())
+ self.assertNotEquals(smaller.keys(), larger.keys())
+
+ # There is an optimization on the zero-element case.
+ self.assertEquals(empty.keys(), empty2.keys())
+ self.assertNotEquals(empty.keys(), smaller.keys())
+
+ # With the same size, an elementwise compare happens
+ self.assertNotEquals(larger.keys(), larger3.keys())
+
def test_missing(self):
# Make sure dict doesn't have a __missing__ method
self.assertEqual(hasattr(dict, "__missing__"), False)
_______________________________________________
Python-3000 mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-3000
Unsubscribe:
http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com