Skip to content

Commit

Permalink
BUG: .iloc[:] and .loc[:] return a copy of the original object #13873 (
Browse files Browse the repository at this point in the history
  • Loading branch information
margaret authored and jreback committed Jun 14, 2017
1 parent a43dcf9 commit b7e7fd3
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 3 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.21.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Conversion
Indexing
^^^^^^^^

- When called with a null slice (e.g. ``df.iloc[:]``), the``iloc`` and ``loc`` indexers return a shallow copy of the original object. Previously they returned the original object. (:issue:`13873`).


I/O
Expand Down
10 changes: 7 additions & 3 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,10 @@ def _getitem_lowerdim(self, tup):
if len(new_key) == 1:
new_key, = new_key

# Slices should return views, but calling iloc/loc with a null
# slice returns a new object.
if is_null_slice(new_key):
return section
# This is an elided recursive call to iloc/loc/etc'
return getattr(section, self.name)[new_key]

Expand Down Expand Up @@ -1250,7 +1254,7 @@ def _get_slice_axis(self, slice_obj, axis=0):
obj = self.obj

if not need_slice(slice_obj):
return obj
return obj.copy(deep=False)
indexer = self._convert_slice_indexer(slice_obj, axis)

if isinstance(indexer, slice):
Expand Down Expand Up @@ -1349,7 +1353,7 @@ def _get_slice_axis(self, slice_obj, axis=0):
""" this is pretty simple as we just have to deal with labels """
obj = self.obj
if not need_slice(slice_obj):
return obj
return obj.copy(deep=False)

labels = obj._get_axis(axis)
indexer = labels.slice_indexer(slice_obj.start, slice_obj.stop,
Expand Down Expand Up @@ -1690,7 +1694,7 @@ def _get_slice_axis(self, slice_obj, axis=0):
obj = self.obj

if not need_slice(slice_obj):
return obj
return obj.copy(deep=False)

slice_obj = self._convert_slice_indexer(slice_obj, axis)
if isinstance(slice_obj, slice):
Expand Down
18 changes: 18 additions & 0 deletions pandas/tests/indexing/test_iloc.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,3 +591,21 @@ def test_iloc_empty_list_indexer_is_ok(self):
tm.assert_frame_equal(df.iloc[[]], df.iloc[:0, :],
check_index_type=True,
check_column_type=True)

def test_identity_slice_returns_new_object(self):
# GH13873
original_df = DataFrame({'a': [1, 2, 3]})
sliced_df = original_df.iloc[:]
assert sliced_df is not original_df

# should be a shallow copy
original_df['a'] = [4, 4, 4]
assert (sliced_df['a'] == 4).all()

original_series = Series([1, 2, 3, 4, 5, 6])
sliced_series = original_series.iloc[:]
assert sliced_series is not original_series

# should also be a shallow copy
original_series[:3] = [7, 8, 9]
assert all(sliced_series[:3] == [7, 8, 9])
25 changes: 25 additions & 0 deletions pandas/tests/indexing/test_loc.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,3 +630,28 @@ def test_loc_empty_list_indexer_is_ok(self):
tm.assert_frame_equal(df.loc[[]], df.iloc[:0, :],
check_index_type=True,
check_column_type=True)

def test_identity_slice_returns_new_object(self):
# GH13873
original_df = DataFrame({'a': [1, 2, 3]})
sliced_df = original_df.loc[:]
assert sliced_df is not original_df
assert original_df[:] is not original_df

# should be a shallow copy
original_df['a'] = [4, 4, 4]
assert (sliced_df['a'] == 4).all()

# These should not return copies
assert original_df is original_df.loc[:, :]
df = DataFrame(np.random.randn(10, 4))
assert df[0] is df.loc[:, 0]

# Same tests for Series
original_series = Series([1, 2, 3, 4, 5, 6])
sliced_series = original_series.loc[:]
assert sliced_series is not original_series
assert original_series[:] is not original_series

original_series[:3] = [7, 8, 9]
assert all(sliced_series[:3] == [7, 8, 9])

0 comments on commit b7e7fd3

Please sign in to comment.