Implement is_array_like
State: closed

- [ ] closes #12764 
- [ ] tests added / passed
- [ ] passes `git diff upstream/master | flake8 --diff`
- [ ] whatsnew entry

Is it worth using this PR to consolidate how the common package is imported across modules? Some files use `from pandas.core.common import *` style whereas others use `import pandas.core.common as com`. Some even use both styles in the same file - is there a style preference and should I go ahead and fix this now? 


Labels:
name: Internals
description: Related to non-user accessible pandas implementation
name: Clean

Comments:
you will have to rebase after I finish reorging types. https://github.com/jreback/pandas/commit/3ef6e8e0ef52476c4b6769263d18ebc7fbf8de6f

should be done in next day or 2.

I'm not sure this is a good idea -- let's finish the discussion of what this means back in #12764 before doing further work here. In particular, most of the code protected by these checks is still specific to NumPy arrays, so using `is_array_like` instead of `isinstance` obfuscates what is going on.

@shoyer you are diving too deep here. This is just an alias at this moment. Later it will need to be changed to actually do something other than `isinsanstance(arr, np.ndarray)`

Just to be clear, once we change `is_array_like`, we'll need to audit every place where it's called. What value do we get from changing it preemptively?

## [Current coverage](https://codecov.io/gh/pydata/pandas/pull/13142?src=pr) is 85.24% (diff: 96.55%)

> Merging [#13142](https://codecov.io/gh/pydata/pandas/pull/13142?src=pr) into [master](https://codecov.io/gh/pydata/pandas/branch/master?src=pr) will increase coverage by **<.01%**

``` diff
@@             master     #13142   diff @@
==========================================
  Files           140        140          
  Lines         50566      50567     +1   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits          43102      43105     +3   
+ Misses         7464       7462     -2   
  Partials          0          0          
```

> Powered by [Codecov](https://codecov.io?src=pr). Last update [f363236...7c17148](https://codecov.io/gh/pydata/pandas/compare/f3632368ed703f3f0586b4f79e26f3eeb4e2a2c2...7c171485aba29bc85acdec45efbb410a531d37b0?src=pr)

can you rebase / update?

though a lot has changed. ok with closing too.

Will update and push something up; hopefully by the end of this weekend.

@wesm any objections?

@sornars also, can you add to pandas.api.types as well

Per the discussion in #12764, I am -1 on calling this function `is_array_like`. We could call this `is_array`, but `isinstance(x, np.ndarray)` is quite short and readable already. Adding a layer of indirection would only make code using this check less obvious, so I am -0 even on `is_array`.

@shoyer so when we have `pa.Array` (the 'new' array object)

you want to go an just change `isinstance(arr, (np.ndarray, pa.Array))`. you think that is more idiomatic / clearer? really?

When we have `pa.Array`, then yes we will probably want to add `is_array` and use it in many cases. But there is no way that `pa.Array` is a 100% drop in replacement for `numpy.ndarray` (e.g., for`dtype` and N-dimensional functionality), so switching every single use of `isinstance(arr, np.ndarray)` to `isinstance(arr, (np.ndarray, pa.Array))` (via `is_array`) is assuredly not going to be what we want.

I'm OK with this function _internally_. Since I predict we'll see fewer and fewer raw ndarrays floating around pandas internals (instead they would be boxed in pandas.Array objects) I expect a lot of this code to go away in the future

I also don't like the `is_arraylike` name (apart from that it should be `is_array_like` to be consistent with other functions). "array-like" has for me a clear meaning of something that is "asarray"-able to an array, so including eg lists. 
So if we include this function, I think `is_array` or even `is_np_array` would be a better fit. However, I follow @shoyer that `isinstance(x, np.ndarray)` is very explicit and already readable as well.

@sornars 
change to `is_array_like` (and I think the meaning in pandas is quite clear; this is very distinct from `is_list_like`). 

pls document that this is an internal function only (IOW, not exposing in the api).

some flake8 errors as well.

We could change the function name to `is_ndarray` to be more clear. My understanding is that the purpose of this is to reduce code duplication / smell, not to expand the definition of what is like an array? For example, Series are array-like, but we wouldn't want to put them in this function? 

well, I think this will make things easier by having the ability to change the array definition in one place. This is meant specifically for testing ndarray (and not list and not Series) things, e.g. the definition _mostly_ could eventually be:

```
def is_array(arr):
    return isinstance(arr, (np.ndarray, pa.Array))
```

with specilizations like:

```
def is_ndarray(arr):
    return isinstance(arr, np.ndarray)

def is_paarray(arr):
    return isnstance(arra, pa.Array)
```

this is really for consistency as we use `is_*` for everything else internally.

In the future that may make sense, but I think we would want to go through and decide specifically where we want to expand the definition of what kind of object passes the `if` condition (i.e. whether to change `is_ndarray` in a particular case to `is_array_zerocopyable`)

fair enough

thanks for the effort @sornars