]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Implement, test and document "key in dict" and "key not in dict".
authorGuido van Rossum <guido@python.org>
Fri, 20 Apr 2001 16:50:40 +0000 (16:50 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 20 Apr 2001 16:50:40 +0000 (16:50 +0000)
I know some people don't like this -- if it's really controversial,
I'll take it out again.  (If it's only Alex Martelli who doesn't like
it, that doesn't count as "real controversial" though. :-)

That's why this is a separate checkin from the iterators stuff I'm
about to check in next.

Doc/lib/libstdtypes.tex
Doc/ref/ref3.tex
Doc/ref/ref5.tex
Lib/test/test_types.py
Objects/dictobject.c

index 79221b8c46878517e1d293ac20f2cfc64f326445..f6786a118792a3b24b3d8551cd618afc6d769873 100644 (file)
@@ -867,9 +867,15 @@ arbitrary objects):
           {(1)}
   \lineiii{\var{a}.clear()}{remove all items from \code{a}}{}
   \lineiii{\var{a}.copy()}{a (shallow) copy of \code{a}}{}
-  \lineiii{\var{a}.has_key(\var{k})}
+  \lineiii{\var{k} \code{in} \var{a}}
           {\code{1} if \var{a} has a key \var{k}, else \code{0}}
           {}
+  \lineiii{\var{k} not in \var{a}}
+          {\code{0} if \var{a} has a key \var{k}, else \code{1}}
+          {}
+  \lineiii{\var{a}.has_key(\var{k})}
+          {Equivalent to \var{k} \code{in} \var{a}}
+          {}
   \lineiii{\var{a}.items()}
           {a copy of \var{a}'s list of (\var{key}, \var{value}) pairs}
           {(2)}
@@ -879,11 +885,11 @@ arbitrary objects):
           {(3)}
   \lineiii{\var{a}.values()}{a copy of \var{a}'s list of values}{(2)}
   \lineiii{\var{a}.get(\var{k}\optional{, \var{x}})}
-          {\code{\var{a}[\var{k}]} if \code{\var{a}.has_key(\var{k})},
+          {\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}}},
            else \var{x}}
           {(4)}
   \lineiii{\var{a}.setdefault(\var{k}\optional{, \var{x}})}
-          {\code{\var{a}[\var{k}]} if \code{\var{a}.has_key(\var{k})},
+          {\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}}},
            else \var{x} (also setting it)}
           {(5)}
   \lineiii{\var{a}.popitem()}
index 1f3afbf35716ba0b907f0a28c845336645ec99ad..adb619ac8996529775e26c44fc3ed9c3711c4127 100644 (file)
@@ -1134,7 +1134,10 @@ multiplication (meaning repetition) by defining the methods
 \method{__add__()}, \method{__radd__()}, \method{__iadd__()},
 \method{__mul__()}, \method{__rmul__()} and \method{__imul__()} described
 below; they should not define \method{__coerce__()} or other numerical
-operators.
+operators.  It is recommended that both mappings and sequences
+implement the \method{__contains__}, to allow efficient use of the
+\code{in} operator; for mappings, \code{in} should be equivalent of
+\method{has_key()}; for sequences, it should search through the values.
 \withsubitem{(mapping object method)}{
   \ttindex{keys()}
   \ttindex{values()}
@@ -1143,7 +1146,8 @@ operators.
   \ttindex{get()}
   \ttindex{clear()}
   \ttindex{copy()}
-  \ttindex{update()}}
+  \ttindex{update()}
+  \ttindex{__contains__()}}
 \withsubitem{(sequence object method)}{
   \ttindex{append()}
   \ttindex{count()}
@@ -1158,7 +1162,8 @@ operators.
   \ttindex{__iadd__()}
   \ttindex{__mul__()}
   \ttindex{__rmul__()}
-  \ttindex{__imul__()}}
+  \ttindex{__imul__()}
+  \ttindex{__contains__()}}
 \withsubitem{(numeric object method)}{\ttindex{__coerce__()}}
 
 \begin{methoddesc}[mapping object]{__len__}{self}
index 5663daaef288b37a5fddd3a220ace0b287136db7..ec0c6b160c25e13e62260d8050c1a36cbaff494c 100644 (file)
@@ -768,7 +768,9 @@ not in \var{s}} returns the negation of \code{\var{x} in \var{s}}.
 The set membership test has traditionally been bound to sequences; an
 object is a member of a set if the set is a sequence and contains an
 element equal to that object.  However, it is possible for an object
-to support membership tests without being a sequence.
+to support membership tests without being a sequence.  In particular,
+dictionaries support memership testing as a nicer way of spelling
+\code{\var{key} in \var{dict}}; other mapping types may follow suit.
 
 For the list and tuple types, \code{\var{x} in \var{y}} is true if and
 only if there exists an index \var{i} such that
index bf356872afc0060a0381a7e4a90a15a175dc0b0a..9df39557f5db81abefa175fa1e29611d543c9502 100644 (file)
@@ -221,6 +221,8 @@ print '6.6 Mappings == Dictionaries'
 d = {}
 if d.keys() != []: raise TestFailed, '{}.keys()'
 if d.has_key('a') != 0: raise TestFailed, '{}.has_key(\'a\')'
+if ('a' in d) != 0: raise TestFailed, "'a' in {}"
+if ('a' not in d) != 1: raise TestFailed, "'a' not in {}"
 if len(d) != 0: raise TestFailed, 'len({})'
 d = {'a': 1, 'b': 2}
 if len(d) != 2: raise TestFailed, 'len(dict)'
@@ -229,6 +231,8 @@ k.sort()
 if k != ['a', 'b']: raise TestFailed, 'dict keys()'
 if d.has_key('a') and d.has_key('b') and not d.has_key('c'): pass
 else: raise TestFailed, 'dict keys()'
+if 'a' in d and 'b' in d and 'c' not in d: pass
+else: raise TestFailed, 'dict keys() # in/not in version'
 if d['a'] != 1 or d['b'] != 2: raise TestFailed, 'dict item'
 d['c'] = 3
 d['a'] = 4
index cc10db04fe4485f79eba55e64133820be21899e7..d00e32617ac68ad617d4fb2607abccde05ae8cc1 100644 (file)
@@ -1292,6 +1292,40 @@ dict_getattr(dictobject *mp, char *name)
        return Py_FindMethod(mapp_methods, (PyObject *)mp, name);
 }
 
+static int
+dict_contains(dictobject *mp, PyObject *key)
+{
+       long hash;
+
+#ifdef CACHE_HASH
+       if (!PyString_Check(key) ||
+           (hash = ((PyStringObject *) key)->ob_shash) == -1)
+#endif
+       {
+               hash = PyObject_Hash(key);
+               if (hash == -1)
+                       return -1;
+       }
+       return (mp->ma_size != 0
+               && (mp->ma_lookup)(mp, key, hash)->me_value != NULL);
+}
+
+staticforward PyObject *dictiter_new(dictobject *);
+
+/* Hack to implement "key in dict" */
+static PySequenceMethods dict_as_sequence = {
+       0,                                      /* sq_length */
+       0,                                      /* sq_concat */
+       0,                                      /* sq_repeat */
+       0,                                      /* sq_item */
+       0,                                      /* sq_slice */
+       0,                                      /* sq_ass_item */
+       0,                                      /* sq_ass_slice */
+       (objobjproc)dict_contains,              /* sq_contains */
+       0,                                      /* sq_inplace_concat */
+       0,                                      /* sq_inplace_repeat */
+};
+
 PyTypeObject PyDict_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,
@@ -1305,7 +1339,7 @@ PyTypeObject PyDict_Type = {
        (cmpfunc)dict_compare,                  /* tp_compare */
        (reprfunc)dict_repr,                    /* tp_repr */
        0,                                      /* tp_as_number */
-       0,                                      /* tp_as_sequence */
+       &dict_as_sequence,                      /* tp_as_sequence */
        &dict_as_mapping,                       /* tp_as_mapping */
        0,                                      /* tp_hash */
        0,                                      /* tp_call */