CLN: avoid getattr(obj, "values", obj)
diff --git a/pandas/_libs/hashtable_func_helper.pxi.in b/pandas/_libs/hashtable_func_helper.pxi.in
index 6e5509a5570e8..c63f368dfae43 100644
--- a/pandas/_libs/hashtable_func_helper.pxi.in
+++ b/pandas/_libs/hashtable_func_helper.pxi.in
@@ -125,7 +125,7 @@ cpdef value_count_{{dtype}}({{c_type}}[:] values, bint dropna):
 {{if dtype == 'object'}}
 def duplicated_{{dtype}}(ndarray[{{dtype}}] values, object keep='first'):
 {{else}}
-def duplicated_{{dtype}}({{c_type}}[:] values, object keep='first'):
+def duplicated_{{dtype}}(const {{c_type}}[:] values, object keep='first'):
 {{endif}}
     cdef:
         int ret = 0
diff --git a/pandas/core/algorithms.py b/pandas/core/algorithms.py
index e6967630b97ac..eca1733b61a52 100644
--- a/pandas/core/algorithms.py
+++ b/pandas/core/algorithms.py
@@ -49,6 +49,7 @@
     ABCExtensionArray,
     ABCIndex,
     ABCIndexClass,
+    ABCMultiIndex,
     ABCSeries,
 )
 from pandas.core.dtypes.missing import isna, na_value_for_dtype
@@ -89,6 +90,10 @@ def _ensure_data(values, dtype=None):
     values : ndarray
     pandas_dtype : str or dtype
     """
+    if not isinstance(values, ABCMultiIndex):
+        # extract_array would raise
+        values = extract_array(values, extract_numpy=True)
+
     # we check some simple dtypes first
     if is_object_dtype(dtype):
         return ensure_object(np.asarray(values)), "object"
@@ -151,7 +156,6 @@ def _ensure_data(values, dtype=None):
     elif is_categorical_dtype(values) and (
         is_categorical_dtype(dtype) or dtype is None
     ):
-        values = getattr(values, "values", values)
         values = values.codes
         dtype = "category"
 
diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py
index 220b70ff71b28..66faca29670cb 100644
--- a/pandas/core/arrays/interval.py
+++ b/pandas/core/arrays/interval.py
@@ -648,7 +648,6 @@ def fillna(self, value=None, method=None, limit=None):
             )
             raise TypeError(msg)
 
-        value = getattr(value, "_values", value)
         self._check_closed_matches(value, name="value")
 
         left = self.left.fillna(value=value.left)
diff --git a/pandas/core/computation/expressions.py b/pandas/core/computation/expressions.py
index 7f93472c766d7..d9cd2c7be0093 100644
--- a/pandas/core/computation/expressions.py
+++ b/pandas/core/computation/expressions.py
@@ -102,8 +102,8 @@ def _evaluate_numexpr(op, op_str, a, b):
             # we were originally called by a reversed op method
             a, b = b, a
 
-        a_value = getattr(a, "values", a)
-        b_value = getattr(b, "values", b)
+        a_value = a
+        b_value = b
 
         result = ne.evaluate(
             f"a_value {op_str} b_value",
diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py
index 3b14921528890..05400f63db972 100644
--- a/pandas/core/window/rolling.py
+++ b/pandas/core/window/rolling.py
@@ -37,6 +37,7 @@
 
 from pandas.core.base import DataError, PandasObject, SelectionMixin, ShallowMixin
 import pandas.core.common as com
+from pandas.core.construction import extract_array
 from pandas.core.indexes.api import Index, ensure_index
 from pandas.core.util.numba_ import NUMBA_FUNC_CACHE
 from pandas.core.window.common import (
@@ -252,7 +253,7 @@ def __iter__(self):
     def _prep_values(self, values: Optional[np.ndarray] = None) -> np.ndarray:
         """Convert input to numpy arrays for Cython routines"""
         if values is None:
-            values = getattr(self._selected_obj, "values", self._selected_obj)
+            values = extract_array(self._selected_obj, extract_numpy=True)
 
         # GH #12373 : rolling functions error on float32 data
         # make sure the data is coerced to float64

xref #27167

@mroeschke can you pls double-check me on the change in window.rolling