Skip to content

Commit

Permalink
ENH: copy kwd for add_suffix/add_prefix (#47934)
Browse files Browse the repository at this point in the history
* ENH: copy kwd for add_suffix/add_prefix

* GH ref

* test series
  • Loading branch information
jbrockmendel authored Aug 10, 2022
1 parent 9a88d42 commit 6db95e7
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 4 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ Other enhancements
- :class:`Series` reducers (e.g. ``min``, ``max``, ``sum``, ``mean``) will now successfully operate when the dtype is numeric and ``numeric_only=True`` is provided; previously this would raise a ``NotImplementedError`` (:issue:`47500`)
- :meth:`RangeIndex.union` now can return a :class:`RangeIndex` instead of a :class:`Int64Index` if the resulting values are equally spaced (:issue:`47557`, :issue:`43885`)
- :meth:`DataFrame.compare` now accepts an argument ``result_names`` to allow the user to specify the result's names of both left and right DataFrame which are being compared. This is by default ``'self'`` and ``'other'`` (:issue:`44354`)
- :meth:`Series.add_suffix`, :meth:`DataFrame.add_suffix`, :meth:`Series.add_prefix` and :meth:`DataFrame.add_prefix` support a ``copy`` argument. If ``False``, the underlying data is not copied in the returned object (:issue:`47934`)

.. ---------------------------------------------------------------------------
.. _whatsnew_150.notable_bug_fixes:
Expand Down
16 changes: 12 additions & 4 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4549,7 +4549,7 @@ def _update_inplace(self, result, verify_is_copy: bool_t = True) -> None:
self._maybe_update_cacher(verify_is_copy=verify_is_copy, inplace=True)

@final
def add_prefix(self: NDFrameT, prefix: str) -> NDFrameT:
def add_prefix(self: NDFrameT, prefix: str, copy: bool_t = True) -> NDFrameT:
"""
Prefix labels with string `prefix`.
Expand All @@ -4560,6 +4560,10 @@ def add_prefix(self: NDFrameT, prefix: str) -> NDFrameT:
----------
prefix : str
The string to add before each label.
copy : bool, default True
Whether to copy the underlying data.
.. versionadded:: 1.5.0
Returns
-------
Expand Down Expand Up @@ -4610,10 +4614,10 @@ def add_prefix(self: NDFrameT, prefix: str) -> NDFrameT:
# expected "NDFrameT")
# error: Argument 1 to "rename" of "NDFrame" has incompatible type
# "**Dict[str, partial[str]]"; expected "Union[str, int, None]"
return self._rename(**mapper) # type: ignore[return-value, arg-type]
return self._rename(**mapper, copy=copy) # type: ignore[return-value, arg-type]

@final
def add_suffix(self: NDFrameT, suffix: str) -> NDFrameT:
def add_suffix(self: NDFrameT, suffix: str, copy: bool_t = True) -> NDFrameT:
"""
Suffix labels with string `suffix`.
Expand All @@ -4624,6 +4628,10 @@ def add_suffix(self: NDFrameT, suffix: str) -> NDFrameT:
----------
suffix : str
The string to add after each label.
copy : bool, default True
Whether to copy the underlying data.
.. versionadded:: 1.5.0
Returns
-------
Expand Down Expand Up @@ -4674,7 +4682,7 @@ def add_suffix(self: NDFrameT, suffix: str) -> NDFrameT:
# expected "NDFrameT")
# error: Argument 1 to "rename" of "NDFrame" has incompatible type
# "**Dict[str, partial[str]]"; expected "Union[str, int, None]"
return self._rename(**mapper) # type: ignore[return-value, arg-type]
return self._rename(**mapper, copy=copy) # type: ignore[return-value, arg-type]

@overload
def sort_values(
Expand Down
53 changes: 53 additions & 0 deletions pandas/tests/frame/methods/test_add_prefix_suffix.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,56 @@ def test_add_prefix_suffix(float_frame):
with_pct_suffix = float_frame.add_suffix("%")
expected = Index([f"{c}%" for c in float_frame.columns])
tm.assert_index_equal(with_pct_suffix.columns, expected)


def test_add_prefix_suffix_copy(float_frame):
# GH#47934
ser = float_frame.iloc[0]

with_prefix = float_frame.add_prefix("foo#", copy=True)
expected = Index([f"foo#{c}" for c in float_frame.columns])
tm.assert_index_equal(with_prefix.columns, expected)
assert not any(
tm.shares_memory(float_frame.iloc[:, i], with_prefix.iloc[:, i])
for i in range(float_frame.shape[1])
)

ser_with_prefix = ser.add_prefix("foo#", copy=True)
tm.assert_index_equal(ser_with_prefix.index, expected)
assert not tm.shares_memory(ser_with_prefix, ser)

with_prefix = float_frame.add_prefix("foo#", copy=False)
expected = Index([f"foo#{c}" for c in float_frame.columns])
tm.assert_index_equal(with_prefix.columns, expected)
assert all(
tm.shares_memory(float_frame.iloc[:, i], with_prefix.iloc[:, i])
for i in range(float_frame.shape[1])
)

ser_with_prefix = ser.add_prefix("foo#", copy=False)
tm.assert_index_equal(ser_with_prefix.index, expected)
assert tm.shares_memory(ser_with_prefix, ser)

with_suffix = float_frame.add_suffix("#foo", copy=True)
expected = Index([f"{c}#foo" for c in float_frame.columns])
tm.assert_index_equal(with_suffix.columns, expected)
assert not any(
tm.shares_memory(float_frame.iloc[:, i], with_suffix.iloc[:, i])
for i in range(float_frame.shape[1])
)

ser_with_suffix = ser.add_suffix("#foo", copy=True)
tm.assert_index_equal(ser_with_suffix.index, expected)
assert not tm.shares_memory(ser_with_suffix, ser)

with_suffix = float_frame.add_suffix("#foo", copy=False)
expected = Index([f"{c}#foo" for c in float_frame.columns])
tm.assert_index_equal(with_suffix.columns, expected)
assert all(
tm.shares_memory(float_frame.iloc[:, i], with_suffix.iloc[:, i])
for i in range(float_frame.shape[1])
)

ser_with_suffix = ser.add_suffix("#foo", copy=False)
tm.assert_index_equal(ser_with_suffix.index, expected)
assert tm.shares_memory(ser_with_suffix, ser)

0 comments on commit 6db95e7

Please sign in to comment.