CLN/INT: avoid getattr(obj, 'values', obj) idiom
We use this idiom quite a bit in the code base:

```
values = getattr(values, 'values', values)
```

One example:

https://github.com/pandas-dev/pandas/blob/ad2e98c3c59233dd8cd5234cead93010e0bd4b8a/pandas/core/algorithms.py#L123

Personally, I find that this makes the code harder to reason about. What kind of object is `values`? What does the `.values` attribute return? (which depends on the object and dtype).

I think a more explicit coding can make things clearer. Sometimes I would find it clearer to just do: 

```
if isinstance(values, ABCSeries):
    values = values.values
```

This is longer, yes, but then it is at least clear that it can potentially be a Series.

Although we should probably even try to avoid that algorithmic code is dealing with a mixture of Series, Index, EA, ndarray. I think, in general, we should nowadays be able to unpack containers in the beginning of / before algorithmic code so we know we only have either ndarray or EA. 
Eg we could have an `ensure_array` that does such explicit checks and ensures the values are ndarray or EA.

cc @jreback @jbrockmendel @TomAugspurger

