Commit 37ee850b authored by Nick Coghlan's avatar Nick Coghlan

Issue 2690: Add support for slicing and negative indices to range objects...

Issue 2690: Add support for slicing and negative indices to range objects (includes precalculation and storage of the range length).

Refer to the tracker issue for the language moratorium implications of this change
parent fad058f0
......@@ -1023,8 +1023,33 @@ are always available. They are listed here in alphabetical order.
>>> list(range(1, 0))
[]
Range objects implement the :class:`collections.Sequence` ABC, and provide
features such as containment tests, element index lookup, slicing and
support for negative indices:
>>> r = range(0, 20, 2)
>>> r
range(0, 20, 2)
>>> 11 in r
False
>>> 10 in r
True
>>> r.index(10)
5
>>> r[5]
10
>>> r[:5]
range(0, 10, 2)
>>> r[-1]
18
Ranges containing absolute values larger than ``sys.maxint`` are permitted
but some features (such as :func:`len`) will raise :exc:`OverflowError`.
.. versionchanged:: 3.2
Testing integers for membership takes constant time instead of iterating
Implement the Sequence ABC
Support slicing and negative indices
Test integers for membership in constant time instead of iterating
through all items.
......
......@@ -313,6 +313,10 @@ Some smaller changes made to the core Python language are:
(Added by Antoine Pitrou, :issue:`10093`.)
.. XXX: Issues #9213 and #2690 make the objects returned by range()
more sequence like in accordance with their registration as
implementing the Sequence ABC
New, Improved, and Deprecated Modules
=====================================
......
......@@ -136,7 +136,12 @@ class RangeTest(unittest.TestCase):
self.assertNotIn(-b, seq)
self.assertEqual(len(seq), 2)
self.assertRaises(OverflowError, len, range(0, sys.maxsize**10))
self.assertRaises(OverflowError, len,
range(-sys.maxsize, sys.maxsize))
self.assertRaises(OverflowError, len,
range(0, 2*sys.maxsize))
self.assertRaises(OverflowError, len,
range(0, sys.maxsize**10))
def test_invalid_invocation(self):
self.assertRaises(TypeError, range)
......@@ -248,6 +253,8 @@ class RangeTest(unittest.TestCase):
always_equal = AlwaysEqual()
self.assertEqual(range(10).count(always_equal), 10)
self.assertEqual(len(range(sys.maxsize, sys.maxsize+10)), 10)
def test_repr(self):
self.assertEqual(repr(range(1)), 'range(0, 1)')
self.assertEqual(repr(range(1, 2)), 'range(1, 2)')
......@@ -349,6 +356,70 @@ class RangeTest(unittest.TestCase):
test_id = "reversed(range({}, {}, {}))".format(start, end, step)
self.assert_iterators_equal(iter1, iter2, test_id, limit=100)
def test_slice(self):
def check(start, stop, step=None):
i = slice(start, stop, step)
self.assertEqual(list(r[i]), list(r)[i])
self.assertEqual(len(r[i]), len(list(r)[i]))
for r in [range(10),
range(0),
range(1, 9, 3),
range(8, 0, -3),
range(sys.maxsize+1, sys.maxsize+10),
]:
check(0, 2)
check(0, 20)
check(1, 2)
check(20, 30)
check(-30, -20)
check(-1, 100, 2)
check(0, -1)
check(-1, -3, -1)
def test_contains(self):
r = range(10)
self.assertIn(0, r)
self.assertIn(1, r)
self.assertIn(5.0, r)
self.assertNotIn(5.1, r)
self.assertNotIn(-1, r)
self.assertNotIn(10, r)
self.assertNotIn("", r)
r = range(9, -1, -1)
self.assertIn(0, r)
self.assertIn(1, r)
self.assertIn(5.0, r)
self.assertNotIn(5.1, r)
self.assertNotIn(-1, r)
self.assertNotIn(10, r)
self.assertNotIn("", r)
r = range(0, 10, 2)
self.assertIn(0, r)
self.assertNotIn(1, r)
self.assertNotIn(5.0, r)
self.assertNotIn(5.1, r)
self.assertNotIn(-1, r)
self.assertNotIn(10, r)
self.assertNotIn("", r)
r = range(9, -1, -2)
self.assertNotIn(0, r)
self.assertIn(1, r)
self.assertIn(5.0, r)
self.assertNotIn(5.1, r)
self.assertNotIn(-1, r)
self.assertNotIn(10, r)
self.assertNotIn("", r)
def test_reverse_iteration(self):
for r in [range(10),
range(0),
range(1, 9, 3),
range(8, 0, -3),
range(sys.maxsize+1, sys.maxsize+10),
]:
self.assertEqual(list(reversed(r)), list(r)[::-1])
def test_main():
test.support.run_unittest(RangeTest)
......
......@@ -782,8 +782,8 @@ class SizeofTest(unittest.TestCase):
# reverse
check(reversed(''), size(h + 'PP'))
# range
check(range(1), size(h + '3P'))
check(range(66000), size(h + '3P'))
check(range(1), size(h + '4P'))
check(range(66000), size(h + '4P'))
# set
# frozenset
PySet_MINSIZE = 8
......
......@@ -10,6 +10,8 @@ What's New in Python 3.2 Beta 1?
Core and Builtins
-----------------
- Issue #2690: Range objects support negative indices and slicing
- Issue #9915: Speed up sorting with a key.
- Issue #7475: Added transform() and untransform() methods to both bytes and
......@@ -652,7 +654,7 @@ Core and Builtins
- Issue #9252: PyImport_Import no longer uses a fromlist hack to return the
module that was imported, but instead gets the module from sys.modules.
- Issue #9212: The range type_items now provides index() and count() methods, to
- Issue #9213: The range type_items now provides index() and count() methods, to
conform to the Sequence ABC. Patch by Daniel Urban and Daniel Stutzbach.
- Issue #7994: Issue a PendingDeprecationWarning if object.__format__ is called
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment