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

Code before:
                try:
                    # If the original grouper was a tuple
                    return [self.indices[name] for name in names]
                except KeyError as err:
                    # turns out it wasn't a tuple
                    msg = (
                        "must supply a same-length tuple to get_group "
                        "with multiple grouping keys"
                    )
                    raise ValueError(msg) from err

            converters = (get_converter(s) for s in index_sample)
            names = (
                tuple(f(n) for f, n in zip(converters, name, strict=True))
                for name in names
            )

        elif any(isna(k) for k in self.indices.keys()):
            converters = [get_converter(name) for name in names]
            names = (converter(name) for converter, name in zip(converters, names))

        else:
            converter = get_converter(index_sample)
            names = (converter(name) for name in names)

        indices = {np.nan if isna(k) else k: v for k, v in self.indices.items()}

        return [indices.get(name, []) for name in names]

    @final
    def _get_index(self, name):
        """
        Safe get index, translate keys for datelike to underlying repr.
        """
        return self._get_indices([name])[0]

    @final
    @cache_readonly
    def _selected_obj(self):
        # Note: _selected_obj is always just `self.obj` for SeriesGroupBy
        if isinstance(self.obj, Series):
            return self.obj

        if self._selection is not None:
            if is_hashable(self._selection):
                # i.e. a single key, so selecting it will return a Series.
                #  In this case, _obj_with_exclusions would wrap the key
                #  in a list and return a single-column DataFrame.
                return self.obj[self._selection]

            # Otherwise _selection is equivalent to _selection_list, so

Review comment (performance):
It seems better to do this on indices cached property directly, and only in the case where there is a NaN value with `if not self.dropna and self.result_index.hasnans`.

Code after:
                    return self.indices[name]
                except KeyError as err:
                    # turns out it wasn't a tuple
                    msg = (
                        "must supply a same-length tuple to get_group "
                        "with multiple grouping keys"
                    )
                    raise ValueError(msg) from err

            converters = (get_converter(s) for s in index_sample)
            name = tuple(f(n) for f, n in zip(converters, name, strict=True))
        else:
            converter = get_converter(index_sample)
            name = converter(name)

        return self.indices.get(name, [])

    @final
    @cache_readonly
    def _selected_obj(self):
        # Note: _selected_obj is always just `self.obj` for SeriesGroupBy
        if isinstance(self.obj, Series):
            return self.obj

        if self._selection is not None:
            if is_hashable(self._selection):
                # i.e. a single key, so selecting it will return a Series.
                #  In this case, _obj_with_exclusions would wrap the key
                #  in a list and return a single-column DataFrame.
                return self.obj[self._selection]

            # Otherwise _selection is equivalent to _selection_list, so
            #  _selected_obj matches _obj_with_exclusions, so we can reuse
            #  that and avoid making a copy.
            return self._obj_with_exclusions

        return self.obj

    @final
    def _dir_additions(self) -> set[str]:
        return self.obj._dir_additions()

    @overload
    def pipe(
        self,
        func: Callable[Concatenate[Self, P], T],
        *args: P.args,
        **kwargs: P.kwargs,
    ) -> T: ...

    @overload