add introspection to range objects (closes #9896)

Patch by Daniel Urban.
This commit is contained in:
Benjamin Peterson 2011-11-05 15:17:52 -04:00
parent 03b0819389
commit 878ce389a0
3 changed files with 44 additions and 2 deletions

View File

@ -1042,7 +1042,9 @@ are always available. They are listed here in alphabetical order.
...]``. If *step* is positive, the last element is the largest ``start + i * ...]``. If *step* is positive, the last element is the largest ``start + i *
step`` less than *stop*; if *step* is negative, the last element is the step`` less than *stop*; if *step* is negative, the last element is the
smallest ``start + i * step`` greater than *stop*. *step* must not be zero smallest ``start + i * step`` greater than *stop*. *step* must not be zero
(or else :exc:`ValueError` is raised). Example: (or else :exc:`ValueError` is raised). Range objects have read-only data
attributes :attr:`start`, :attr:`stop` and :attr:`step` which return the
argument values (or their default). Example:
>>> list(range(10)) >>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@ -1100,6 +1102,9 @@ are always available. They are listed here in alphabetical order.
sequence of values they define (instead of comparing based on sequence of values they define (instead of comparing based on
object identity). object identity).
.. versionadded:: 3.3
The :attr:`start`, :attr:`stop` and :attr:`step` attributes.
.. function:: repr(object) .. function:: repr(object)

View File

@ -560,6 +560,35 @@ class RangeTest(unittest.TestCase):
range(0) >= range(0) range(0) >= range(0)
def test_attributes(self):
# test the start, stop and step attributes of range objects
self.assert_attrs(range(0), 0, 0, 1)
self.assert_attrs(range(10), 0, 10, 1)
self.assert_attrs(range(-10), 0, -10, 1)
self.assert_attrs(range(0, 10, 1), 0, 10, 1)
self.assert_attrs(range(0, 10, 3), 0, 10, 3)
self.assert_attrs(range(10, 0, -1), 10, 0, -1)
self.assert_attrs(range(10, 0, -3), 10, 0, -3)
def assert_attrs(self, rangeobj, start, stop, step):
self.assertEqual(rangeobj.start, start)
self.assertEqual(rangeobj.stop, stop)
self.assertEqual(rangeobj.step, step)
with self.assertRaises(AttributeError):
rangeobj.start = 0
with self.assertRaises(AttributeError):
rangeobj.stop = 10
with self.assertRaises(AttributeError):
rangeobj.step = 1
with self.assertRaises(AttributeError):
del rangeobj.start
with self.assertRaises(AttributeError):
del rangeobj.stop
with self.assertRaises(AttributeError):
del rangeobj.step
def test_main(): def test_main():
test.support.run_unittest(RangeTest) test.support.run_unittest(RangeTest)

View File

@ -1,6 +1,7 @@
/* Range object implementation */ /* Range object implementation */
#include "Python.h" #include "Python.h"
#include "structmember.h"
/* Support objects whose length is > PY_SSIZE_T_MAX. /* Support objects whose length is > PY_SSIZE_T_MAX.
@ -880,6 +881,13 @@ static PyMethodDef range_methods[] = {
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
static PyMemberDef range_members[] = {
{"start", T_OBJECT_EX, offsetof(rangeobject, start), READONLY},
{"stop", T_OBJECT_EX, offsetof(rangeobject, stop), READONLY},
{"step", T_OBJECT_EX, offsetof(rangeobject, step), READONLY},
{0}
};
PyTypeObject PyRange_Type = { PyTypeObject PyRange_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
"range", /* Name of this type */ "range", /* Name of this type */
@ -909,7 +917,7 @@ PyTypeObject PyRange_Type = {
range_iter, /* tp_iter */ range_iter, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
range_methods, /* tp_methods */ range_methods, /* tp_methods */
0, /* tp_members */ range_members, /* tp_members */
0, /* tp_getset */ 0, /* tp_getset */
0, /* tp_base */ 0, /* tp_base */
0, /* tp_dict */ 0, /* tp_dict */