Skip to content

Commit 137a886

Browse files
topper-123jreback
authored andcommitted
REF: Refactor signature of RangeIndex._simple_new (#26722)
1 parent 5d0ff69 commit 137a886

File tree

4 files changed

+42
-42
lines changed

4 files changed

+42
-42
lines changed

doc/source/whatsnew/v0.25.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ Performance Improvements
525525
- Improved performance of :meth:`Series.searchsorted`. The speedup is especially large when the dtype is
526526
int8/int16/int32 and the searched key is within the integer bounds for the dtype (:issue:`22034`)
527527
- Improved performance of :meth:`pandas.core.groupby.GroupBy.quantile` (:issue:`20405`)
528-
- Improved performance of slicing and other selected operation on a :class:`RangeIndex` (:issue:`26565`, :issue:`26617`)
528+
- Improved performance of slicing and other selected operation on a :class:`RangeIndex` (:issue:`26565`, :issue:`26617`, :issue:`26722`)
529529
- Improved performance of :meth:`read_csv` by faster tokenizing and faster parsing of small float numbers (:issue:`25784`)
530530
- Improved performance of :meth:`read_csv` by faster parsing of N/A and boolean values (:issue:`25804`)
531531
- Improved performance of :attr:`IntervalIndex.is_monotonic`, :attr:`IntervalIndex.is_monotonic_increasing` and :attr:`IntervalIndex.is_monotonic_decreasing` by removing conversion to :class:`MultiIndex` (:issue:`24813`)

pandas/core/indexes/base.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,7 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
273273
if isinstance(data, RangeIndex):
274274
return RangeIndex(start=data, copy=copy, dtype=dtype, name=name)
275275
elif isinstance(data, range):
276-
return RangeIndex.from_range(data, copy=copy, dtype=dtype,
277-
name=name)
276+
return RangeIndex.from_range(data, dtype=dtype, name=name)
278277

279278
# categorical
280279
elif is_categorical_dtype(data) or is_categorical_dtype(dtype):

pandas/core/indexes/range.py

+34-37
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import numpy as np
88

9-
from pandas._libs import index as libindex, lib
9+
from pandas._libs import index as libindex
1010
import pandas.compat as compat
1111
from pandas.compat.numpy import function as nv
1212
from pandas.util._decorators import Appender, cache_readonly
@@ -82,16 +82,15 @@ def __new__(cls, start=None, stop=None, step=None,
8282
"removed in a future version.",
8383
FutureWarning, stacklevel=2)
8484
if fastpath:
85-
return cls._simple_new(start, stop, step, name=name)
85+
return cls._simple_new(range(start, stop, step), name=name)
8686

8787
cls._validate_dtype(dtype)
8888

8989
# RangeIndex
9090
if isinstance(start, RangeIndex):
91-
if name is None:
92-
name = start.name
93-
return cls._simple_new(name=name,
94-
**dict(start._get_data_as_items()))
91+
name = start.name if name is None else name
92+
start = start._range
93+
return cls._simple_new(start, dtype=dtype, name=name)
9594

9695
# validate the arguments
9796
if com._all_none(start, stop, step):
@@ -108,10 +107,11 @@ def __new__(cls, start=None, stop=None, step=None,
108107
if step == 0:
109108
raise ValueError("Step must not be zero")
110109

111-
return cls._simple_new(start, stop, step, name)
110+
rng = range(start, stop, step)
111+
return cls._simple_new(rng, dtype=dtype, name=name)
112112

113113
@classmethod
114-
def from_range(cls, data, name=None, dtype=None, **kwargs):
114+
def from_range(cls, data, name=None, dtype=None):
115115
"""
116116
Create RangeIndex from a range object.
117117
@@ -124,26 +124,21 @@ def from_range(cls, data, name=None, dtype=None, **kwargs):
124124
'{0}(...) must be called with object coercible to a '
125125
'range, {1} was passed'.format(cls.__name__, repr(data)))
126126

127-
start, stop, step = data.start, data.stop, data.step
128-
return cls(start, stop, step, dtype=dtype, name=name, **kwargs)
127+
cls._validate_dtype(dtype)
128+
return cls._simple_new(data, dtype=dtype, name=name)
129129

130130
@classmethod
131-
def _simple_new(cls, start, stop=None, step=None, name=None,
132-
dtype=None, **kwargs):
131+
def _simple_new(cls, values, name=None, dtype=None, **kwargs):
133132
result = object.__new__(cls)
134133

135134
# handle passed None, non-integers
136-
if start is None and stop is None:
135+
if values is None:
137136
# empty
138-
start, stop, step = 0, 0, 1
137+
values = range(0, 0, 1)
138+
elif not isinstance(values, range):
139+
return Index(values, dtype=dtype, name=name, **kwargs)
139140

140-
if start is None or not is_integer(start):
141-
try:
142-
return cls(start, stop, step, name=name, **kwargs)
143-
except TypeError:
144-
return Index(start, stop, step, name=name, **kwargs)
145-
146-
result._range = range(start, stop or 0, step or 1)
141+
result._range = values
147142

148143
result.name = name
149144
for k, v in kwargs.items():
@@ -360,8 +355,7 @@ def tolist(self):
360355
def _shallow_copy(self, values=None, **kwargs):
361356
if values is None:
362357
name = kwargs.get("name", self.name)
363-
return self._simple_new(
364-
name=name, **dict(self._get_data_as_items()))
358+
return self._simple_new(self._range, name=name)
365359
else:
366360
kwargs.setdefault('name', self.name)
367361
return self._int64index._shallow_copy(values, **kwargs)
@@ -480,11 +474,13 @@ def intersection(self, other, sort=False):
480474
tmp_start = first.start + (second.start - first.start) * \
481475
first.step // gcd * s
482476
new_step = first.step * second.step // gcd
483-
new_index = self._simple_new(tmp_start, int_high, new_step)
477+
new_range = range(tmp_start, int_high, new_step)
478+
new_index = self._simple_new(new_range)
484479

485480
# adjust index to limiting interval
486481
new_start = new_index._min_fitting_element(int_low)
487-
new_index = self._simple_new(new_start, new_index.stop, new_index.step)
482+
new_range = range(new_start, new_index.stop, new_index.step)
483+
new_index = self._simple_new(new_range)
488484

489485
if (self.step < 0 and other.step < 0) is not (new_index.step < 0):
490486
new_index = new_index[::-1]
@@ -609,23 +605,22 @@ def __getitem__(self, key):
609605
"""
610606
Conserve RangeIndex type for scalar and slice keys.
611607
"""
612-
if is_scalar(key):
613-
if not lib.is_integer(key):
614-
raise IndexError("only integers, slices (`:`), "
615-
"ellipsis (`...`), numpy.newaxis (`None`) "
616-
"and integer or boolean "
617-
"arrays are valid indices")
608+
if isinstance(key, slice):
609+
new_range = self._range[key]
610+
return self._simple_new(new_range, name=self.name)
611+
elif is_integer(key):
618612
new_key = int(key)
619613
try:
620614
return self._range[new_key]
621615
except IndexError:
622616
raise IndexError("index {key} is out of bounds for axis 0 "
623617
"with size {size}".format(key=key,
624618
size=len(self)))
625-
if isinstance(key, slice):
626-
new_range = self._range[key]
627-
return self.from_range(new_range, name=self.name)
628-
619+
elif is_scalar(key):
620+
raise IndexError("only integers, slices (`:`), "
621+
"ellipsis (`...`), numpy.newaxis (`None`) "
622+
"and integer or boolean "
623+
"arrays are valid indices")
629624
# fall back to Int64Index
630625
return super().__getitem__(key)
631626

@@ -640,10 +635,12 @@ def __floordiv__(self, other):
640635
start = self.start // other
641636
step = self.step // other
642637
stop = start + len(self) * step
643-
return self._simple_new(start, stop, step, name=self.name)
638+
new_range = range(start, stop, step or 1)
639+
return self._simple_new(new_range, name=self.name)
644640
if len(self) == 1:
645641
start = self.start // other
646-
return self._simple_new(start, start + 1, 1, name=self.name)
642+
new_range = range(start, start + 1, 1)
643+
return self._simple_new(new_range, name=self.name)
647644
return self._int64index // other
648645

649646
def all(self) -> bool:

pandas/tests/indexes/test_range.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ def test_constructor_same(self):
9494

9595
def test_constructor_range(self):
9696

97-
with pytest.raises(TypeError):
98-
RangeIndex(range(1, 5, 2))
97+
msg = "Value needs to be a scalar value, was type <class 'range'>"
98+
with pytest.raises(TypeError, match=msg):
99+
result = RangeIndex(range(1, 5, 2))
99100

100101
result = RangeIndex.from_range(range(1, 5, 2))
101102
expected = RangeIndex(1, 5, 2)
@@ -120,6 +121,9 @@ def test_constructor_range(self):
120121

121122
with pytest.raises(TypeError):
122123
Index(range(1, 5, 2), dtype='float64')
124+
msg = r'^from_range\(\) got an unexpected keyword argument'
125+
with pytest.raises(TypeError, match=msg):
126+
pd.RangeIndex.from_range(range(10), copy=True)
123127

124128
def test_constructor_name(self):
125129
# GH12288

0 commit comments

Comments
 (0)