Skip to content

Commit e889b94

Browse files
authored
REF: implement Index._view, Index._rename (#39651)
1 parent aa2ab5e commit e889b94

File tree

18 files changed

+65
-69
lines changed

18 files changed

+65
-69
lines changed

asv_bench/benchmarks/categoricals.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ def time_get_loc(self):
323323
self.index.get_loc(self.category)
324324

325325
def time_shallow_copy(self):
326-
self.index._shallow_copy()
326+
self.index._view()
327327

328328
def time_align(self):
329329
pd.DataFrame({"a": self.series, "b": self.series[:500]})

asv_bench/benchmarks/period.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def time_get_loc(self):
8686
self.index.get_loc(self.period)
8787

8888
def time_shallow_copy(self):
89-
self.index._shallow_copy()
89+
self.index._view()
9090

9191
def time_series_loc(self):
9292
self.series.loc[self.period]

asv_bench/benchmarks/timedelta.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def time_get_loc(self):
7474
self.index.get_loc(self.timedelta)
7575

7676
def time_shallow_copy(self):
77-
self.index._shallow_copy()
77+
self.index._view()
7878

7979
def time_series_loc(self):
8080
self.series.loc[self.timedelta]

pandas/core/frame.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8917,7 +8917,7 @@ def _count_level(self, level: Level, axis: Axis = 0, numeric_only=False):
89178917
level = count_axis._get_level_number(level)
89188918

89198919
level_name = count_axis._names[level]
8920-
level_index = count_axis.levels[level]._shallow_copy(name=level_name)
8920+
level_index = count_axis.levels[level]._rename(name=level_name)
89218921
level_codes = ensure_int64(count_axis.codes[level])
89228922
counts = lib.count_level_2d(mask, level_codes, len(level_index), axis=axis)
89238923

pandas/core/indexes/base.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ def _get_attributes_dict(self):
582582
"""
583583
return {k: getattr(self, k, None) for k in self._attributes}
584584

585-
def _shallow_copy(self, values=None, name: Hashable = no_default):
585+
def _shallow_copy(self, values, name: Hashable = no_default):
586586
"""
587587
Create a new Index with the same class as the caller, don't copy the
588588
data, use the same object attributes with passed in attributes taking
@@ -597,13 +597,26 @@ def _shallow_copy(self, values=None, name: Hashable = no_default):
597597
"""
598598
name = self.name if name is no_default else name
599599

600-
if values is not None:
601-
return self._simple_new(values, name=name)
600+
return self._simple_new(values, name=name)
601+
602+
def _view(self: _IndexT) -> _IndexT:
603+
"""
604+
fastpath to make a shallow copy, i.e. new object with same data.
605+
"""
606+
result = self._simple_new(self._values, name=self.name)
602607

603-
result = self._simple_new(self._values, name=name)
604608
result._cache = self._cache
605609
return result
606610

611+
@final
612+
def _rename(self: _IndexT, name: Hashable) -> _IndexT:
613+
"""
614+
fastpath for rename if new name is already validated.
615+
"""
616+
result = self._view()
617+
result._name = name
618+
return result
619+
607620
@final
608621
def is_(self, other) -> bool:
609622
"""
@@ -732,7 +745,7 @@ def view(self, cls=None):
732745
if cls is not None and not hasattr(cls, "_typ"):
733746
result = self._data.view(cls)
734747
else:
735-
result = self._shallow_copy()
748+
result = self._view()
736749
if isinstance(result, Index):
737750
result._id = self._id
738751
return result
@@ -938,9 +951,10 @@ def copy(
938951
"""
939952
name = self._validate_names(name=name, names=names, deep=deep)[0]
940953
if deep:
941-
new_index = self._shallow_copy(self._data.copy(), name=name)
954+
new_data = self._data.copy()
955+
new_index = type(self)._simple_new(new_data, name=name)
942956
else:
943-
new_index = self._shallow_copy(name=name)
957+
new_index = self._rename(name=name)
944958

945959
if dtype:
946960
warnings.warn(
@@ -1236,7 +1250,7 @@ def to_series(self, index=None, name=None):
12361250
from pandas import Series
12371251

12381252
if index is None:
1239-
index = self._shallow_copy()
1253+
index = self._view()
12401254
if name is None:
12411255
name = self.name
12421256

@@ -1494,7 +1508,7 @@ def set_names(self, names, level=None, inplace: bool = False):
14941508
if inplace:
14951509
idx = self
14961510
else:
1497-
idx = self._shallow_copy()
1511+
idx = self._view()
14981512

14991513
idx._set_names(names, level=level)
15001514
if not inplace:
@@ -2439,7 +2453,7 @@ def fillna(self, value=None, downcast=None):
24392453
# no need to care metadata other than name
24402454
# because it can't have freq if
24412455
return Index(result, name=self.name)
2442-
return self._shallow_copy()
2456+
return self._view()
24432457

24442458
def dropna(self, how="any"):
24452459
"""
@@ -2461,7 +2475,7 @@ def dropna(self, how="any"):
24612475
if self.hasnans:
24622476
res_values = self._values[~self._isnan]
24632477
return type(self)._simple_new(res_values, name=self.name)
2464-
return self._shallow_copy()
2478+
return self._view()
24652479

24662480
# --------------------------------------------------------------------
24672481
# Uniqueness Methods
@@ -2490,7 +2504,7 @@ def unique(self, level=None):
24902504
self._validate_index_level(level)
24912505

24922506
if self.is_unique:
2493-
return self._shallow_copy()
2507+
return self._view()
24942508

24952509
result = super().unique()
24962510
return self._shallow_copy(result)
@@ -2543,7 +2557,7 @@ def drop_duplicates(self, keep="first"):
25432557
Index(['cow', 'beetle', 'hippo'], dtype='object')
25442558
"""
25452559
if self.is_unique:
2546-
return self._shallow_copy()
2560+
return self._view()
25472561

25482562
return super().drop_duplicates(keep=keep)
25492563

@@ -3809,15 +3823,15 @@ def join(self, other, how="left", level=None, return_indexers=False, sort=False)
38093823
)
38103824

38113825
if len(other) == 0 and how in ("left", "outer"):
3812-
join_index = self._shallow_copy()
3826+
join_index = self._view()
38133827
if return_indexers:
38143828
rindexer = np.repeat(-1, len(join_index))
38153829
return join_index, None, rindexer
38163830
else:
38173831
return join_index
38183832

38193833
if len(self) == 0 and how in ("right", "outer"):
3820-
join_index = other._shallow_copy()
3834+
join_index = other._view()
38213835
if return_indexers:
38223836
lindexer = np.repeat(-1, len(join_index))
38233837
return join_index, lindexer, None

pandas/core/indexes/category.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -214,13 +214,10 @@ def _simple_new(cls, values: Categorical, name: Optional[Hashable] = None):
214214

215215
# --------------------------------------------------------------------
216216

217-
# error: Argument 1 of "_shallow_copy" is incompatible with supertype
218-
# "ExtensionIndex"; supertype defines the argument type as
219-
# "Optional[ExtensionArray]" [override]
220217
@doc(Index._shallow_copy)
221-
def _shallow_copy( # type:ignore[override]
218+
def _shallow_copy(
222219
self,
223-
values: Optional[Categorical] = None,
220+
values: Categorical,
224221
name: Hashable = no_default,
225222
):
226223
name = self.name if name is no_default else name

pandas/core/indexes/datetimelike.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,8 @@ def _fast_union(self: _T, other: _T, sort=None) -> _T:
797797
dates = concat_compat((left._values, right_chunk))
798798
# With sort being False, we can't infer that result.freq == self.freq
799799
# TODO: no tests rely on the _with_freq("infer"); needed?
800-
result = self._shallow_copy(dates)._with_freq("infer")
800+
result = type(self)._simple_new(dates, name=self.name)
801+
result = result._with_freq("infer")
801802
return result
802803
else:
803804
left, right = other, self

pandas/core/indexes/datetimes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ def to_series(self, keep_tz=lib.no_default, index=None, name=None):
469469
from pandas import Series
470470

471471
if index is None:
472-
index = self._shallow_copy()
472+
index = self._view()
473473
if name is None:
474474
name = self.name
475475

pandas/core/indexes/extension.py

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
"""
22
Shared methods for Index subclasses backed by ExtensionArray.
33
"""
4-
from typing import Hashable, List, Optional, TypeVar
4+
from typing import List, TypeVar
55

66
import numpy as np
77

8-
from pandas._libs import lib
98
from pandas.compat.numpy import function as nv
109
from pandas.errors import AbstractMethodError
1110
from pandas.util._decorators import cache_readonly, doc
@@ -213,19 +212,6 @@ class ExtensionIndex(Index):
213212
__le__ = _make_wrapped_comparison_op("__le__")
214213
__ge__ = _make_wrapped_comparison_op("__ge__")
215214

216-
@doc(Index._shallow_copy)
217-
def _shallow_copy(
218-
self, values: Optional[ExtensionArray] = None, name: Hashable = lib.no_default
219-
):
220-
name = self.name if name is lib.no_default else name
221-
222-
if values is not None:
223-
return self._simple_new(values, name=name)
224-
225-
result = self._simple_new(self._data, name=name)
226-
result._cache = self._cache
227-
return result
228-
229215
@property
230216
def _has_complex_internals(self) -> bool:
231217
# used to avoid libreduction code paths, which raise or require conversion

pandas/core/indexes/multi.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -735,9 +735,7 @@ def levels(self):
735735
# Use cache_readonly to ensure that self.get_locs doesn't repeatedly
736736
# create new IndexEngine
737737
# https://github.com/pandas-dev/pandas/issues/31648
738-
result = [
739-
x._shallow_copy(name=name) for x, name in zip(self._levels, self._names)
740-
]
738+
result = [x._rename(name=name) for x, name in zip(self._levels, self._names)]
741739
for level in result:
742740
# disallow midx.levels[0].name = "foo"
743741
level._no_setting_name = True
@@ -764,13 +762,13 @@ def _set_levels(
764762

765763
if level is None:
766764
new_levels = FrozenList(
767-
ensure_index(lev, copy=copy)._shallow_copy() for lev in levels
765+
ensure_index(lev, copy=copy)._view() for lev in levels
768766
)
769767
else:
770768
level_numbers = [self._get_level_number(lev) for lev in level]
771769
new_levels_list = list(self._levels)
772770
for lev_num, lev in zip(level_numbers, levels):
773-
new_levels_list[lev_num] = ensure_index(lev, copy=copy)._shallow_copy()
771+
new_levels_list[lev_num] = ensure_index(lev, copy=copy)._view()
774772
new_levels = FrozenList(new_levels_list)
775773

776774
if verify_integrity:
@@ -886,7 +884,7 @@ def set_levels(self, levels, level=None, inplace=None, verify_integrity=True):
886884
if inplace:
887885
idx = self
888886
else:
889-
idx = self._shallow_copy()
887+
idx = self._view()
890888
idx._reset_identity()
891889
idx._set_levels(
892890
levels, level=level, validate=True, verify_integrity=verify_integrity
@@ -1046,7 +1044,7 @@ def set_codes(self, codes, level=None, inplace=None, verify_integrity=True):
10461044
if inplace:
10471045
idx = self
10481046
else:
1049-
idx = self._shallow_copy()
1047+
idx = self._view()
10501048
idx._reset_identity()
10511049
idx._set_codes(codes, level=level, verify_integrity=verify_integrity)
10521050
if not inplace:
@@ -1082,17 +1080,17 @@ def _constructor(self):
10821080
return type(self).from_tuples
10831081

10841082
@doc(Index._shallow_copy)
1085-
def _shallow_copy(self, values=None, name=lib.no_default):
1083+
def _shallow_copy(self, values, name=lib.no_default):
10861084
names = name if name is not lib.no_default else self.names
10871085

1088-
if values is not None:
1089-
return type(self).from_tuples(values, sortorder=None, names=names)
1086+
return type(self).from_tuples(values, sortorder=None, names=names)
10901087

1088+
def _view(self: MultiIndex) -> MultiIndex:
10911089
result = type(self)(
10921090
levels=self.levels,
10931091
codes=self.codes,
10941092
sortorder=None,
1095-
names=names,
1093+
names=self.names,
10961094
verify_integrity=False,
10971095
)
10981096
result._cache = self._cache.copy()
@@ -3652,7 +3650,7 @@ def astype(self, dtype, copy=True):
36523650
"is not supported"
36533651
)
36543652
elif copy is True:
3655-
return self._shallow_copy()
3653+
return self._view()
36563654
return self
36573655

36583656
def _validate_fill_value(self, item):

pandas/core/indexes/numeric.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ def _maybe_cast_slice_bound(self, label, side: str, kind):
111111
# ----------------------------------------------------------------
112112

113113
@doc(Index._shallow_copy)
114-
def _shallow_copy(self, values=None, name: Hashable = lib.no_default):
115-
if values is not None and not self._can_hold_na and values.dtype.kind == "f":
114+
def _shallow_copy(self, values, name: Hashable = lib.no_default):
115+
if not self._can_hold_na and values.dtype.kind == "f":
116116
name = self.name if name is lib.no_default else name
117117
# Ensure we are not returning an Int64Index with float data:
118118
return Float64Index._simple_new(values, name=name)

pandas/core/indexes/range.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -422,22 +422,22 @@ def __iter__(self):
422422
yield from self._range
423423

424424
@doc(Int64Index._shallow_copy)
425-
def _shallow_copy(self, values=None, name: Hashable = no_default):
425+
def _shallow_copy(self, values, name: Hashable = no_default):
426426
name = self.name if name is no_default else name
427427

428-
if values is not None:
429-
if values.dtype.kind == "f":
430-
return Float64Index(values, name=name)
431-
return Int64Index._simple_new(values, name=name)
428+
if values.dtype.kind == "f":
429+
return Float64Index(values, name=name)
430+
return Int64Index._simple_new(values, name=name)
432431

433-
result = self._simple_new(self._range, name=name)
432+
def _view(self: RangeIndex) -> RangeIndex:
433+
result = type(self)._simple_new(self._range, name=self.name)
434434
result._cache = self._cache
435435
return result
436436

437437
@doc(Int64Index.copy)
438438
def copy(self, name=None, deep=False, dtype: Optional[Dtype] = None, names=None):
439439
name = self._validate_names(name=name, names=names, deep=deep)[0]
440-
new_index = self._shallow_copy(name=name)
440+
new_index = self._rename(name=name)
441441

442442
if dtype:
443443
warnings.warn(

pandas/core/indexes/timedeltas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def __new__(
138138
if copy:
139139
return data.copy()
140140
else:
141-
return data._shallow_copy()
141+
return data._view()
142142

143143
# - Cases checked above all return/raise before reaching here - #
144144

pandas/core/reshape/reshape.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ def get_new_values(self, values, fill_value=None):
261261
def get_new_columns(self, value_columns):
262262
if value_columns is None:
263263
if self.lift == 0:
264-
return self.removed_level._shallow_copy(name=self.removed_name)
264+
return self.removed_level._rename(name=self.removed_name)
265265

266266
lev = self.removed_level.insert(0, item=self.removed_level._na_value)
267267
return lev.rename(self.removed_name)
@@ -639,7 +639,7 @@ def _convert_level_number(level_num, columns):
639639
new_names = this.columns.names[:-1]
640640
new_columns = MultiIndex.from_tuples(unique_groups, names=new_names)
641641
else:
642-
new_columns = this.columns.levels[0]._shallow_copy(name=this.columns.names[0])
642+
new_columns = this.columns.levels[0]._rename(name=this.columns.names[0])
643643
unique_groups = new_columns
644644

645645
# time to ravel the values

pandas/tests/indexes/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ def test_shallow_copy_shares_cache(self):
733733
# GH32669, GH36840
734734
idx = self.create_index()
735735
idx.get_loc(idx[0]) # populates the _cache.
736-
shallow_copy = idx._shallow_copy()
736+
shallow_copy = idx._view()
737737

738738
assert shallow_copy._cache is idx._cache
739739

pandas/tests/indexes/multi/test_copy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def test_copy(idx):
3030

3131

3232
def test_shallow_copy(idx):
33-
i_copy = idx._shallow_copy()
33+
i_copy = idx._view()
3434

3535
assert_multiindex_copied(i_copy, idx)
3636

0 commit comments

Comments
 (0)