35
35
36
36
from pandas .core .dtypes .common import (
37
37
ensure_platform_int ,
38
- ensure_python_int ,
38
+ ensure_python_intfloat ,
39
39
is_float ,
40
40
is_integer ,
41
+ is_numeric_dtype ,
41
42
is_scalar ,
42
- is_signed_integer_dtype ,
43
43
is_timedelta64_dtype ,
44
44
)
45
45
from pandas .core .dtypes .generic import ABCTimedeltaIndex
50
50
from pandas .core .construction import extract_array
51
51
import pandas .core .indexes .base as ibase
52
52
from pandas .core .indexes .base import maybe_extract_name
53
+ from pandas .core .indexes .float_range import float_range
53
54
from pandas .core .indexes .numeric import (
54
55
Float64Index ,
55
56
Int64Index ,
@@ -67,20 +68,20 @@ class RangeIndex(NumericIndex):
67
68
"""
68
69
Immutable Index implementing a monotonic integer range.
69
70
70
- RangeIndex is a memory-saving special case of Int64Index limited to
71
- representing monotonic ranges. Using RangeIndex may in some instances
72
- improve computing speed.
71
+ RangeIndex is a memory-saving special case of NumericIndex
72
+ limited to representing monotonic ranges. Using RangeIndex may in some
73
+ instances improve computing speed.
73
74
74
- This is the default index type used
75
- by DataFrame and Series when no explicit index is provided by the user.
75
+ This is the default index type used by DataFrame and Series when no
76
+ explicit index is provided by the user.
76
77
77
78
Parameters
78
79
----------
79
- start : int (default: 0), range, or other RangeIndex instance
80
- If int and "stop" is not given, interpreted as "stop" instead.
81
- stop : int (default: 0)
82
- step : int (default: 1)
83
- dtype : np.int64
80
+ start : int|float (default: 0), range, or other RangeIndex instance
81
+ If int|float and "stop" is not given, interpreted as "stop" instead.
82
+ stop : int|float (default: 0)
83
+ step : int|float (default: 1)
84
+ dtype : np.int64|np.float64
84
85
Unused, accepted for homogeneity with other index types.
85
86
copy : bool, default False
86
87
Unused, accepted for homogeneity with other index types.
@@ -101,16 +102,17 @@ class RangeIndex(NumericIndex):
101
102
--------
102
103
Index : The base pandas Index type.
103
104
Int64Index : Index of int64 data.
105
+ Float64Index : Index of float64 data
104
106
"""
105
107
106
108
_typ = "rangeindex"
107
- _dtype_validation_metadata = (is_signed_integer_dtype , "signed integer " )
108
- _range : range
109
+ _dtype_validation_metadata = (is_numeric_dtype , "numeric type " )
110
+ _range : range | float_range
109
111
_is_backward_compat_public_numeric_index : bool = False
110
112
111
113
@property
112
- def _engine_type (self ) -> type [libindex .Int64Engine ]:
113
- return libindex .Int64Engine
114
+ def _engine_type (self ) -> type [libindex .IndexEngine ]:
115
+ return libindex .Float64Engine if is_float ( self . start ) else libindex . Int64Engine
114
116
115
117
# --------------------------------------------------------------------
116
118
# Constructors
@@ -135,25 +137,36 @@ def __new__(
135
137
136
138
# validate the arguments
137
139
if com .all_none (start , stop , step ):
138
- raise TypeError ("RangeIndex(...) must be called with integers" )
140
+ raise TypeError ("RangeIndex(...) must be called with integers/floats " )
139
141
140
- start = ensure_python_int (start ) if start is not None else 0
142
+ # check if any of the arguments is a float
143
+ coerce_float = any (is_float (attr ) for attr in [start , stop , step ])
144
+
145
+ start = ensure_python_intfloat (start , coerce_float ) if start is not None else 0
141
146
142
147
if stop is None :
143
- start , stop = 0 , start
148
+ start , stop = 0.0 if coerce_float else 0 , start
144
149
else :
145
- stop = ensure_python_int (stop )
146
-
147
- step = ensure_python_int (step ) if step is not None else 1
150
+ stop = ensure_python_intfloat (stop , coerce_float )
151
+
152
+ step = (
153
+ ensure_python_intfloat (step , coerce_float )
154
+ if step is not None
155
+ else 1.0
156
+ if coerce_float
157
+ else 1
158
+ )
148
159
if step == 0 :
149
160
raise ValueError ("Step must not be zero" )
150
161
151
- rng = range (start , stop , step )
162
+ rng = (
163
+ float_range (start , stop , step ) if coerce_float else range (start , stop , step )
164
+ )
152
165
return cls ._simple_new (rng , name = name )
153
166
154
167
@classmethod
155
168
def from_range (
156
- cls , data : range , name = None , dtype : Dtype | None = None
169
+ cls , data : range | float_range , name = None , dtype : Dtype | None = None
157
170
) -> RangeIndex :
158
171
"""
159
172
Create RangeIndex from a range object.
@@ -162,7 +175,7 @@ def from_range(
162
175
-------
163
176
RangeIndex
164
177
"""
165
- if not isinstance (data , range ):
178
+ if not isinstance (data , range ) and not isinstance ( data , float_range ) :
166
179
raise TypeError (
167
180
f"{ cls .__name__ } (...) must be called with object coercible to a "
168
181
f"range, { repr (data )} was passed"
@@ -171,10 +184,12 @@ def from_range(
171
184
return cls ._simple_new (data , name = name )
172
185
173
186
@classmethod
174
- def _simple_new (cls , values : range , name : Hashable = None ) -> RangeIndex :
187
+ def _simple_new (
188
+ cls , values : range | float_range , name : Hashable = None
189
+ ) -> RangeIndex :
175
190
result = object .__new__ (cls )
176
191
177
- assert isinstance (values , range )
192
+ assert isinstance (values , range ) or isinstance ( values , float_range )
178
193
179
194
result ._range = values
180
195
result ._name = name
@@ -184,12 +199,12 @@ def _simple_new(cls, values: range, name: Hashable = None) -> RangeIndex:
184
199
185
200
# --------------------------------------------------------------------
186
201
187
- # error: Return type "Type[Int64Index ]" of "_constructor" incompatible with return
202
+ # error: Return type "Type[NumericIndex ]" of "_constructor" incompatible with return
188
203
# type "Type[RangeIndex]" in supertype "Index"
189
204
@cache_readonly
190
- def _constructor (self ) -> type [Int64Index ]: # type: ignore[override]
205
+ def _constructor (self ) -> type [NumericIndex ]: # type: ignore[override]
191
206
"""return the class to use for construction"""
192
- return Int64Index
207
+ return Float64Index if is_float ( self . start ) else Int64Index
193
208
194
209
# error: Signature of "_data" incompatible with supertype "Index"
195
210
@cache_readonly
@@ -199,7 +214,12 @@ def _data(self) -> np.ndarray: # type: ignore[override]
199
214
200
215
The constructed array is saved in ``_cache``.
201
216
"""
202
- return np .arange (self .start , self .stop , self .step , dtype = np .int64 )
217
+ return np .arange (
218
+ self .start ,
219
+ self .stop ,
220
+ self .step ,
221
+ dtype = np .float64 if is_float (self .start ) else np .int64 ,
222
+ )
203
223
204
224
def _get_data_as_items (self ):
205
225
"""return a list of tuples of start, stop, step"""
@@ -352,7 +372,7 @@ def memory_usage(self, deep: bool = False) -> int:
352
372
353
373
@property
354
374
def dtype (self ) -> np .dtype :
355
- return np .dtype (np .int64 )
375
+ return np .dtype (np .float64 if is_float ( self . start ) else np . int64 )
356
376
357
377
@property
358
378
def is_unique (self ) -> bool :
@@ -370,14 +390,14 @@ def is_monotonic_decreasing(self) -> bool:
370
390
def __contains__ (self , key : Any ) -> bool :
371
391
hash (key )
372
392
try :
373
- key = ensure_python_int (key )
393
+ key = ensure_python_intfloat (key , True )
374
394
except TypeError :
375
395
return False
376
396
return key in self ._range
377
397
378
398
@property
379
399
def inferred_type (self ) -> str :
380
- return "integer"
400
+ return "float" if is_float ( self . start ) else " integer"
381
401
382
402
# --------------------------------------------------------------------
383
403
# Indexing Methods
0 commit comments