Index: Objects/rangeobject.c =================================================================== --- Objects/rangeobject.c (revision 84880) +++ Objects/rangeobject.c (working copy) @@ -1,6 +1,7 @@ /* Range object implementation */ #include "Python.h" +#include "structmember.h" /* Support objects whose length is > PY_SSIZE_T_MAX. @@ -434,6 +435,13 @@ {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 = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "range", /* Name of this type */ @@ -463,7 +471,7 @@ range_iter, /* tp_iter */ 0, /* tp_iternext */ range_methods, /* tp_methods */ - 0, /* tp_members */ + range_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ Index: Doc/library/stdtypes.rst =================================================================== --- Doc/library/stdtypes.rst (revision 84880) +++ Doc/library/stdtypes.rst (working copy) @@ -1554,6 +1554,11 @@ object will always take the same amount of memory, no matter the size of the range it represents. There are no consistent performance advantages. +Range objects have the read-only attributes :attr:`start`, :attr:`stop` and +:attr:`step`, corresponding to the constructor arguments. + + .. versionadded:: 3.2 + Range objects have relatively little behavior: they support indexing, iteration, the :func:`len` function, and the following methods. Index: Doc/library/functions.rst =================================================================== --- Doc/library/functions.rst (revision 84880) +++ Doc/library/functions.rst (working copy) @@ -943,7 +943,9 @@ ...]``. 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 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 merely return + the argument values (or their default). Example: >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] @@ -964,7 +966,10 @@ Testing integers for membership takes constant time instead of iterating through all items. + .. versionadded:: 3.2 + The :attr:`start`, :attr:`stop` and :attr:`step` attributes. + .. function:: repr(object) Return a string containing a printable representation of an object. For many Index: Lib/test/test_range.py =================================================================== --- Lib/test/test_range.py (revision 84880) +++ Lib/test/test_range.py (working copy) @@ -191,6 +191,35 @@ test_id = "reversed(range({}, {}, {}))".format(start, end, step) self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + 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.assertEquals(rangeobj.start, start) + self.assertEquals(rangeobj.stop, stop) + self.assertEquals(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(): test.support.run_unittest(RangeTest)