diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 5bba7ab67b2bf..7f16b7c2513fb 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -276,6 +276,22 @@ def _init_mgr( mgr = mgr.astype(dtype=dtype) return mgr + @classmethod + def _from_mgr(cls, mgr: Manager): + """ + Fastpath to create a new DataFrame/Series from just a BlockManager/ArrayManager. + + Notes + ----- + Skips setting `_flags` attribute; caller is responsible for doing so. + """ + obj = cls.__new__(cls) + object.__setattr__(obj, "_is_copy", None) + object.__setattr__(obj, "_mgr", mgr) + object.__setattr__(obj, "_item_cache", {}) + object.__setattr__(obj, "_attrs", {}) + return obj + # ---------------------------------------------------------------------- # attrs and flags diff --git a/pandas/core/groupby/ops.py b/pandas/core/groupby/ops.py index 7fb6e98fb176e..a61e8872a7ce7 100644 --- a/pandas/core/groupby/ops.py +++ b/pandas/core/groupby/ops.py @@ -1013,7 +1013,13 @@ def _chop(self, sdata: Series, slice_obj: slice) -> Series: # fastpath equivalent to `sdata.iloc[slice_obj]` mgr = sdata._mgr.get_slice(slice_obj) # __finalize__ not called here, must be applied by caller if applicable - return sdata._constructor(mgr, name=sdata.name, fastpath=True) + + # fastpath equivalent to: + # `return sdata._constructor(mgr, name=sdata.name, fastpath=True)` + obj = type(sdata)._from_mgr(mgr) + object.__setattr__(obj, "_flags", sdata._flags) + object.__setattr__(obj, "_name", sdata._name) + return obj class FrameSplitter(DataSplitter): @@ -1030,7 +1036,11 @@ def _chop(self, sdata: DataFrame, slice_obj: slice) -> DataFrame: # return sdata.iloc[:, slice_obj] mgr = sdata._mgr.get_slice(slice_obj, axis=1 - self.axis) # __finalize__ not called here, must be applied by caller if applicable - return sdata._constructor(mgr) + + # fastpath equivalent to `return sdata._constructor(mgr)` + obj = type(sdata)._from_mgr(mgr) + object.__setattr__(obj, "_flags", sdata._flags) + return obj def get_splitter(