Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0dbb4fb

Browse files
committed
Implement, test and document "key in dict" and "key not in dict".
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.
1 parent 78fe530 commit 0dbb4fb

5 files changed

Lines changed: 59 additions & 8 deletions

File tree

Doc/lib/libstdtypes.tex

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -867,9 +867,15 @@ \subsection{Mapping Types \label{typesmapping}}
867867
{(1)}
868868
\lineiii{\var{a}.clear()}{remove all items from \code{a}}{}
869869
\lineiii{\var{a}.copy()}{a (shallow) copy of \code{a}}{}
870-
\lineiii{\var{a}.has_key(\var{k})}
870+
\lineiii{\var{k} \code{in} \var{a}}
871871
{\code{1} if \var{a} has a key \var{k}, else \code{0}}
872872
{}
873+
\lineiii{\var{k} not in \var{a}}
874+
{\code{0} if \var{a} has a key \var{k}, else \code{1}}
875+
{}
876+
\lineiii{\var{a}.has_key(\var{k})}
877+
{Equivalent to \var{k} \code{in} \var{a}}
878+
{}
873879
\lineiii{\var{a}.items()}
874880
{a copy of \var{a}'s list of (\var{key}, \var{value}) pairs}
875881
{(2)}
@@ -879,11 +885,11 @@ \subsection{Mapping Types \label{typesmapping}}
879885
{(3)}
880886
\lineiii{\var{a}.values()}{a copy of \var{a}'s list of values}{(2)}
881887
\lineiii{\var{a}.get(\var{k}\optional{, \var{x}})}
882-
{\code{\var{a}[\var{k}]} if \code{\var{a}.has_key(\var{k})},
888+
{\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}}},
883889
else \var{x}}
884890
{(4)}
885891
\lineiii{\var{a}.setdefault(\var{k}\optional{, \var{x}})}
886-
{\code{\var{a}[\var{k}]} if \code{\var{a}.has_key(\var{k})},
892+
{\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}}},
887893
else \var{x} (also setting it)}
888894
{(5)}
889895
\lineiii{\var{a}.popitem()}

Doc/ref/ref3.tex

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,10 @@ \subsection{Emulating sequence and mapping types\label{sequence-types}}
11341134
\method{__add__()}, \method{__radd__()}, \method{__iadd__()},
11351135
\method{__mul__()}, \method{__rmul__()} and \method{__imul__()} described
11361136
below; they should not define \method{__coerce__()} or other numerical
1137-
operators.
1137+
operators. It is recommended that both mappings and sequences
1138+
implement the \method{__contains__}, to allow efficient use of the
1139+
\code{in} operator; for mappings, \code{in} should be equivalent of
1140+
\method{has_key()}; for sequences, it should search through the values.
11381141
\withsubitem{(mapping object method)}{
11391142
\ttindex{keys()}
11401143
\ttindex{values()}
@@ -1143,7 +1146,8 @@ \subsection{Emulating sequence and mapping types\label{sequence-types}}
11431146
\ttindex{get()}
11441147
\ttindex{clear()}
11451148
\ttindex{copy()}
1146-
\ttindex{update()}}
1149+
\ttindex{update()}
1150+
\ttindex{__contains__()}}
11471151
\withsubitem{(sequence object method)}{
11481152
\ttindex{append()}
11491153
\ttindex{count()}
@@ -1158,7 +1162,8 @@ \subsection{Emulating sequence and mapping types\label{sequence-types}}
11581162
\ttindex{__iadd__()}
11591163
\ttindex{__mul__()}
11601164
\ttindex{__rmul__()}
1161-
\ttindex{__imul__()}}
1165+
\ttindex{__imul__()}
1166+
\ttindex{__contains__()}}
11621167
\withsubitem{(numeric object method)}{\ttindex{__coerce__()}}
11631168

11641169
\begin{methoddesc}[mapping object]{__len__}{self}

Doc/ref/ref5.tex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,9 @@ \section{Comparisons\label{comparisons}}
768768
The set membership test has traditionally been bound to sequences; an
769769
object is a member of a set if the set is a sequence and contains an
770770
element equal to that object. However, it is possible for an object
771-
to support membership tests without being a sequence.
771+
to support membership tests without being a sequence. In particular,
772+
dictionaries support memership testing as a nicer way of spelling
773+
\code{\var{key} in \var{dict}}; other mapping types may follow suit.
772774

773775
For the list and tuple types, \code{\var{x} in \var{y}} is true if and
774776
only if there exists an index \var{i} such that

Lib/test/test_types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ def myComparison(x,y):
221221
d = {}
222222
if d.keys() != []: raise TestFailed, '{}.keys()'
223223
if d.has_key('a') != 0: raise TestFailed, '{}.has_key(\'a\')'
224+
if ('a' in d) != 0: raise TestFailed, "'a' in {}"
225+
if ('a' not in d) != 1: raise TestFailed, "'a' not in {}"
224226
if len(d) != 0: raise TestFailed, 'len({})'
225227
d = {'a': 1, 'b': 2}
226228
if len(d) != 2: raise TestFailed, 'len(dict)'
@@ -229,6 +231,8 @@ def myComparison(x,y):
229231
if k != ['a', 'b']: raise TestFailed, 'dict keys()'
230232
if d.has_key('a') and d.has_key('b') and not d.has_key('c'): pass
231233
else: raise TestFailed, 'dict keys()'
234+
if 'a' in d and 'b' in d and 'c' not in d: pass
235+
else: raise TestFailed, 'dict keys() # in/not in version'
232236
if d['a'] != 1 or d['b'] != 2: raise TestFailed, 'dict item'
233237
d['c'] = 3
234238
d['a'] = 4

Objects/dictobject.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,40 @@ dict_getattr(dictobject *mp, char *name)
12921292
return Py_FindMethod(mapp_methods, (PyObject *)mp, name);
12931293
}
12941294

1295+
static int
1296+
dict_contains(dictobject *mp, PyObject *key)
1297+
{
1298+
long hash;
1299+
1300+
#ifdef CACHE_HASH
1301+
if (!PyString_Check(key) ||
1302+
(hash = ((PyStringObject *) key)->ob_shash) == -1)
1303+
#endif
1304+
{
1305+
hash = PyObject_Hash(key);
1306+
if (hash == -1)
1307+
return -1;
1308+
}
1309+
return (mp->ma_size != 0
1310+
&& (mp->ma_lookup)(mp, key, hash)->me_value != NULL);
1311+
}
1312+
1313+
staticforward PyObject *dictiter_new(dictobject *);
1314+
1315+
/* Hack to implement "key in dict" */
1316+
static PySequenceMethods dict_as_sequence = {
1317+
0, /* sq_length */
1318+
0, /* sq_concat */
1319+
0, /* sq_repeat */
1320+
0, /* sq_item */
1321+
0, /* sq_slice */
1322+
0, /* sq_ass_item */
1323+
0, /* sq_ass_slice */
1324+
(objobjproc)dict_contains, /* sq_contains */
1325+
0, /* sq_inplace_concat */
1326+
0, /* sq_inplace_repeat */
1327+
};
1328+
12951329
PyTypeObject PyDict_Type = {
12961330
PyObject_HEAD_INIT(&PyType_Type)
12971331
0,
@@ -1305,7 +1339,7 @@ PyTypeObject PyDict_Type = {
13051339
(cmpfunc)dict_compare, /* tp_compare */
13061340
(reprfunc)dict_repr, /* tp_repr */
13071341
0, /* tp_as_number */
1308-
0, /* tp_as_sequence */
1342+
&dict_as_sequence, /* tp_as_sequence */
13091343
&dict_as_mapping, /* tp_as_mapping */
13101344
0, /* tp_hash */
13111345
0, /* tp_call */

0 commit comments

Comments
 (0)