diff -r b392a39970bb Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py Sun Sep 30 22:48:20 2012 +0300 +++ b/Lib/test/test_builtin.py Tue Oct 02 19:30:51 2012 +0200 @@ -1337,6 +1337,13 @@ return {'a':2} __dict__ = property(fget=getDict) + class C_vars_slots(object): + __slots__ = 'x', 'y' + z = 1 + + class C_vars_dictslots(object): + __slots__ = '__dict__', 'foo' + def test_vars(self): self.assertEqual(set(vars()), set(dir())) self.assertEqual(set(vars(sys)), set(dir(sys))) @@ -1346,6 +1353,22 @@ self.assertRaises(TypeError, vars, 42) self.assertEqual(vars(self.C_get_vars()), {'a':2}) + # when no attribute is defined, should return a empty dict() + slot_test = self.C_vars_slots() + slot_test.x = 1 + self.assertEqual(vars(self.C_vars_slots()), {}) + self.assertEqual(vars(slot_test), {'x': 1}) + # any new attribute shall be present + slot_test.y = 2 + self.assertEqual(vars(slot_test), {'x': 1, 'y':2}) + # having both __dict__ and __slots__, prevales __dict__ + slot_test = self.C_vars_dictslots() + slot_test.cheese = 'spam' + self.assertEqual(vars(slot_test), {'cheese': 'spam'}) + slot_test = type('slot_test', (self.C_vars_slots, ), {'a': 1, 'b': 2}) + self.assertIn('a', set(vars(slot_test))) + self.assertIn('b', set(vars(slot_test))) + def test_zip(self): a = (1, 2, 3) b = (4, 5, 6) diff -r b392a39970bb Python/bltinmodule.c --- a/Python/bltinmodule.c Sun Sep 30 22:48:20 2012 +0300 +++ b/Python/bltinmodule.c Tue Oct 02 19:30:51 2012 +0200 @@ -1899,6 +1899,8 @@ { PyObject *v = NULL; PyObject *d; + _Py_IDENTIFIER(__dict__); + _Py_IDENTIFIER(__slots__); if (!PyArg_UnpackTuple(args, "vars", 0, 1, &v)) return NULL; @@ -1908,19 +1910,47 @@ if (!PyErr_Occurred()) PyErr_SetString(PyExc_SystemError, "vars(): no locals!?"); - } - else + } else Py_INCREF(d); - } - else { - _Py_IDENTIFIER(__dict__); + } else { d = _PyObject_GetAttrId(v, &PyId___dict__); + /* if no __dict__ attribute is found, try fetching __slots__ */ if (d == NULL) { - PyErr_SetString(PyExc_TypeError, - "vars() argument must have __dict__ attribute"); - return NULL; + PyObject *slots = _PyObject_GetAttrId(v, &PyId___slots__); + PyObject *iter, *item, *value; + + if (slots == NULL) { + PyErr_SetString(PyExc_TypeError, + "vars() argument must have __dict__ or\ + __slots__ attribute"); + return NULL; + } else + PyErr_Clear(); + + iter = PyObject_GetIter(slots); + if (iter == NULL) + return NULL; + + d = PyDict_New(); + if (d == NULL) + return NULL; + + while ((item = PyIter_Next(iter))) { + value = PyObject_GetAttr(v, item); + if (value == NULL) + PyErr_Clear(); + else if (PyDict_SetItem(d, item, value) != 0) { + Py_DECREF(d); + break; + } + Py_DECREF(item); + Py_XDECREF(value); + } + Py_DECREF(iter); + Py_DECREF(slots); } } + return d; } @@ -1928,7 +1958,10 @@ "vars([object]) -> dictionary\n\ \n\ Without arguments, equivalent to locals().\n\ -With an argument, equivalent to object.__dict__."); +With an argument, equivalent to object.__dict__\ +if present, object.__slots__ otherwise.\n\ +In case neither of the two is present raises\ +TypeError.\n"); static PyObject* builtin_sum(PyObject *self, PyObject *args)