def _partitioner(
        self,
        *,
        func: Callable,
        dim: Hashable | None,
        sep: str | bytes | Any | None,
    ) -> T_DataArray:
        """
        Implements logic for `partition` and `rpartition`.
        """
        sep = self._stringify(sep)

        if dim is None:
            listfunc = lambda x, isep: list(func(x, isep))
            return self._apply(func=listfunc, func_args=(sep,), dtype=np.object_)

        # _apply breaks on an empty array in this case
        if not self._obj.size:
            return self._obj.copy().expand_dims({dim: 0}, axis=-1)

        arrfunc = lambda x, isep: np.array(func(x, isep), dtype=self._obj.dtype)

        # dtype MUST be object or strings can be truncated
        # See: https://github.com/numpy/numpy/issues/8352
        return duck_array_ops.astype(
            self._apply(
                func=arrfunc,
                func_args=(sep,),
                dtype=np.object_,
                output_core_dims=[[dim]],
                output_sizes={dim: 3},
            ),
            self._obj.dtype.kind,
        )

        Implements logic for `partition` and `rpartition`.
        
xarray/core/accessor_str.py