Repository: pandas-dev/pandas
File: pandas/core/groupby/generic.py (Python)

Code before:
    aggfunc: AggScalar

    __slots__ = ()

    def __new__(
        cls,
        column: Hashable,
        aggfunc: Callable[..., Any] | str,
        *args: Any,
        **kwargs: Any,
    ) -> Self:
        if (
            callable(aggfunc)
            and not getattr(aggfunc, "_is_wrapped", False)
            and (args or kwargs)
        ):
            original_func = aggfunc

            def wrapped(*call_args: Any, **call_kwargs: Any) -> Any:
                series = call_args[0]
                final_args = call_args[1:] + args
                final_kwargs = {**kwargs, **call_kwargs}
                return original_func(series, *final_args, **final_kwargs)

            wrapped._is_wrapped = True  # type: ignore[attr-defined]
            aggfunc = wrapped
        return super().__new__(cls, (column, aggfunc))


@set_module("pandas.api.typing")
class SeriesGroupBy(GroupBy[Series]):
    def _wrap_agged_manager(self, mgr: Manager) -> Series:
        out = self.obj._constructor_from_mgr(mgr, axes=mgr.axes)
        out._name = self.obj.name
        return out

    def _get_data_to_aggregate(
        self, *, numeric_only: bool = False, name: str | None = None
    ) -> SingleBlockManager:
        ser = self._obj_with_exclusions
        single = ser._mgr
        if numeric_only and not is_numeric_dtype(ser.dtype):
            # GH#41291 match Series behavior
            kwd_name = "numeric_only"
            raise TypeError(
                f"Cannot use {kwd_name}=True with "
                f"{type(self).__name__}.{name} and non-numeric dtypes."
            )
        return single

    _agg_examples_doc = dedent(

Review comment (suggestion):
In line with the above, this changes the `aggfunc` which is a public attribute. Instead, I think we should utilize args/kwargs in places within pandas that accept a NamedAgg

Code after:
    args: tuple[Any, ...] = ()
    kwargs: dict[str, Any] = dataclasses.field(default_factory=dict)

    def __init__(
        self,
        column: Hashable,
        aggfunc: Callable[..., Any] | str,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        self.column = column
        self.aggfunc = aggfunc
        self.args = args
        self.kwargs = kwargs

    def __getitem__(self, key: int) -> Any:
        """Provide backward-compatible tuple-style access."""
        if key == 0:
            return self.column
        elif key == 1:
            return self.aggfunc
        elif key == 2:
            return self.args
        elif key == 3:
            return self.kwargs
        raise IndexError("index out of range")


@set_module("pandas.api.typing")
class SeriesGroupBy(GroupBy[Series]):
    def _wrap_agged_manager(self, mgr: Manager) -> Series:
        out = self.obj._constructor_from_mgr(mgr, axes=mgr.axes)
        out._name = self.obj.name
        return out

    def _get_data_to_aggregate(
        self, *, numeric_only: bool = False, name: str | None = None
    ) -> SingleBlockManager:
        ser = self._obj_with_exclusions
        single = ser._mgr
        if numeric_only and not is_numeric_dtype(ser.dtype):
            # GH#41291 match Series behavior
            kwd_name = "numeric_only"
            raise TypeError(
                f"Cannot use {kwd_name}=True with "
                f"{type(self).__name__}.{name} and non-numeric dtypes."
            )
        return single

    _agg_examples_doc = dedent(
        """