Skip to content

Commit

Permalink
add introspection to range objects (closes python#9896)
Browse files Browse the repository at this point in the history
Patch by Daniel Urban.
  • Loading branch information
benjaminp committed Nov 5, 2011
1 parent 03b0819 commit 878ce38
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
7 changes: 6 additions & 1 deletion Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
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 return the
argument values (or their default). Example:

>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Expand Down Expand Up @@ -1100,6 +1102,9 @@ are always available. They are listed here in alphabetical order.
sequence of values they define (instead of comparing based on
object identity).

.. versionadded:: 3.3
The :attr:`start`, :attr:`stop` and :attr:`step` attributes.


.. function:: repr(object)

Expand Down
29 changes: 29 additions & 0 deletions Lib/test/test_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,35 @@ def test_comparison(self):
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():
test.support.run_unittest(RangeTest)

Expand Down
10 changes: 9 additions & 1 deletion Objects/rangeobject.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* Range object implementation */

#include "Python.h"
#include "structmember.h"

/* Support objects whose length is > PY_SSIZE_T_MAX.
Expand Down Expand Up @@ -880,6 +881,13 @@ static PyMethodDef range_methods[] = {
{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 */
Expand Down Expand Up @@ -909,7 +917,7 @@ PyTypeObject PyRange_Type = {
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 */
Expand Down

0 comments on commit 878ce38

Please sign in to comment.