summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-09-02 08:22:48 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-09-02 08:22:48 (GMT)
commit25786c0851da8665bdbba948ddb16b23a040bbb2 (patch)
tree6bbe5fef549dc5105b642567c9ce1e0e87a0b94f
parent1b8ca0d87a806a5098496ad4864a975707cd6bac (diff)
downloadcpython-25786c0851da8665bdbba948ddb16b23a040bbb2.zip
cpython-25786c0851da8665bdbba948ddb16b23a040bbb2.tar.gz
cpython-25786c0851da8665bdbba948ddb16b23a040bbb2.tar.bz2
Make dictionary() a real constructor. Accepts at most one argument, "a
mapping object", in the same sense dict.update(x) requires of x (that x has a keys() method and a getitem). Questionable: The other type constructors accept a keyword argument, so I did that here too (e.g., dictionary(mapping={1:2}) works). But type_call doesn't pass the keyword args to the tp_new slot (it passes NULL), it only passes them to the tp_init slot, so getting at them required adding a tp_init slot to dicts. Looks like that makes the normal case (i.e., no args at all) a little slower (the time it takes to call dict.tp_init and have it figure out there's nothing to do).
-rw-r--r--Lib/test/test_descr.py52
-rw-r--r--Objects/dictobject.c31
2 files changed, 80 insertions, 3 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index f495a37..f6b9e1b 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1,6 +1,6 @@
# Test descriptor-related enhancements
-from test_support import verify, verbose
+from test_support import verify, verbose, TestFailed
from copy import deepcopy
def testunop(a, res, expr="len(a)", meth="__len__"):
@@ -123,6 +123,55 @@ def dicts():
verify(eval(d.__repr__(), {}) == d)
testset2op({1:2,3:4}, 2, 3, {1:2,2:3,3:4}, "a[b]=c", "__setitem__")
+def dict_constructor():
+ if verbose:
+ print "Testing dictionary constructor ..."
+ d = dictionary()
+ verify(d == {})
+ d = dictionary({})
+ verify(d == {})
+ d = dictionary(mapping={})
+ verify(d == {})
+ d = dictionary({1: 2, 'a': 'b'})
+ verify(d == {1: 2, 'a': 'b'})
+ for badarg in 0, 0L, 0j, "0", [0], (0,):
+ try:
+ dictionary(badarg)
+ except TypeError:
+ pass
+ else:
+ raise TestFailed("no TypeError from dictionary(%r)" % badarg)
+ try:
+ dictionary(senseless={})
+ except TypeError:
+ pass
+ else:
+ raise TestFailed("no TypeError from dictionary(senseless={}")
+
+ try:
+ dictionary({}, {})
+ except TypeError:
+ pass
+ else:
+ raise TestFailed("no TypeError from dictionary({}, {})")
+
+ class Mapping:
+ dict = {1:2, 3:4, 'a':1j}
+
+ def __getitem__(self, i):
+ return self.dict[i]
+
+ try:
+ dictionary(Mapping())
+ except TypeError:
+ pass
+ else:
+ raise TestFailed("no TypeError from dictionary(incomplete mapping)")
+
+ Mapping.keys = lambda self: self.dict.keys()
+ d = dictionary(mapping=Mapping())
+ verify(d == Mapping.dict)
+
binops = {
'add': '+',
'sub': '-',
@@ -1299,6 +1348,7 @@ def inherits():
def all():
lists()
dicts()
+ dict_constructor()
ints()
longs()
floats()
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index e8a564e..91d2c53 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1692,12 +1692,39 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return self;
}
+static int
+dict_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *arg = NULL;
+ static char *kwlist[] = {"mapping", 0};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:dictionary",
+ kwlist, &arg))
+ return -1;
+ if (arg != NULL) {
+ if (PyDict_Merge(self, arg, 1) < 0) {
+ /* An error like "AttibuteError: keys" is too
+ cryptic in this context. */
+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument must be of a mapping type");
+ }
+ return -1;
+ }
+ }
+ return 0;
+}
+
static PyObject *
dict_iter(dictobject *dict)
{
return dictiter_new(dict, select_key);
}
+static char dictionary_doc[] =
+"dictionary() -> new empty dictionary\n"
+"dictionary(mapping) -> new dict initialized from mapping's key+value pairs";
+
PyTypeObject PyDict_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
@@ -1721,7 +1748,7 @@ PyTypeObject PyDict_Type = {
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
- "dictionary type", /* tp_doc */
+ dictionary_doc, /* tp_doc */
(traverseproc)dict_traverse, /* tp_traverse */
(inquiry)dict_tp_clear, /* tp_clear */
dict_richcompare, /* tp_richcompare */
@@ -1736,7 +1763,7 @@ PyTypeObject PyDict_Type = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
- 0, /* tp_init */
+ (initproc)dict_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
dict_new, /* tp_new */
};