# python: how to identify if a variable is an array or a scalar

## Question:

I have a function that takes the argument `NBins`

. I want to make a call to this function with a scalar `50`

or an array `[0, 10, 20, 30]`

. How can I identify within the function, what the length of `NBins`

is? or said differently, if it is a scalar or a vector?

I tried this:

```
>>> N=[2,3,5]
>>> P = 5
>>> len(N)
3
>>> len(P)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
>>>
```

As you see, I can’t apply `len`

to `P`

, since it’s not an array…. Is there something like `isarray`

or `isscalar`

in python?

thanks

## Answers:

```
>>> import collections.abc
>>> isinstance([0, 10, 20, 30], collections.abc.Sequence)
True
>>> isinstance(50, collections.abc.Sequence)
False
```

**note**: `isinstance`

also supports a tuple of classes, check `type(x) in (..., ...)`

should be avoided and is unnecessary.

You may also wanna check `not isinstance(x, (str, unicode))`

As noted by @2080 and also here this won’t work for `numpy`

arrays. eg.

```
>>> import collections.abc
>>> import numpy as np
>>> isinstance((1, 2, 3), collections.abc.Sequence)
True
>>> isinstance(np.array([1, 2, 3]), collections.abc.Sequence)
False
```

In which case you may try the answer from @jpaddison3:

```
>>> hasattr(np.array([1, 2, 3]), "__len__")
True
>>> hasattr([1, 2, 3], "__len__")
True
>>> hasattr((1, 2, 3), "__len__")
True
```

However as noted here, this is not perfect either, and will incorrectly (at least according to me) classify dictionaries as sequences whereas `isinstance`

with `collections.abc.Sequence`

classifies correctly:

```
>>> hasattr({"a": 1}, "__len__")
True
>>> from numpy.distutils.misc_util import is_sequence
>>> is_sequence({"a": 1})
True
>>> isinstance({"a": 1}, collections.abc.Sequence)
False
```

You could customise your solution to something like this, add more types to `isinstance`

depending on your needs:

```
>>> isinstance(np.array([1, 2, 3]), (collections.abc.Sequence, np.ndarray))
True
>>> isinstance([1, 2, 3], (collections.abc.Sequence, np.ndarray))
True
```

While, @jamylak’s approach is the better one, here is an alternative approach

```
>>> N=[2,3,5]
>>> P = 5
>>> type(P) in (tuple, list)
False
>>> type(N) in (tuple, list)
True
```

```
>>> N=[2,3,5]
>>> P = 5
>>> type(P)==type(0)
True
>>> type([1,2])==type(N)
True
>>> type(P)==type([1,2])
False
```

You can check data type of variable.

```
N = [2,3,5]
P = 5
type(P)
```

It will give you out put as data type of P.

```
<type 'int'>
```

So that you can differentiate that it is an integer or an array.

Another alternative approach (use of class **name** property):

```
N = [2,3,5]
P = 5
type(N).__name__ == 'list'
True
type(P).__name__ == 'int'
True
type(N).__name__ in ('list', 'tuple')
True
```

No need to import anything.

Previous answers assume that the array is a python standard list. As someone who uses numpy often, I’d recommend a very pythonic test of:

```
if hasattr(N, "__len__")
```

Combining @jamylak and @jpaddison3’s answers together, if you need to be robust against numpy arrays as the input and handle them in the same way as lists, you should use

```
import numpy as np
isinstance(P, (list, tuple, np.ndarray))
```

This is robust against subclasses of list, tuple and numpy arrays.

And if you want to be robust against all other subclasses of sequence as well (not just list and tuple), use

```
import collections
import numpy as np
isinstance(P, (collections.Sequence, np.ndarray))
```

Why should you do things this way with `isinstance`

and not compare `type(P)`

with a target value? Here is an example, where we make and study the behaviour of `NewList`

, a trivial subclass of list.

```
>>> class NewList(list):
... isThisAList = '???'
...
>>> x = NewList([0,1])
>>> y = list([0,1])
>>> print x
[0, 1]
>>> print y
[0, 1]
>>> x==y
True
>>> type(x)
<class '__main__.NewList'>
>>> type(x) is list
False
>>> type(y) is list
True
>>> type(x).__name__
'NewList'
>>> isinstance(x, list)
True
```

Despite `x`

and `y`

comparing as equal, handling them by `type`

would result in different behaviour. However, since `x`

is an instance of a subclass of `list`

, using `isinstance(x,list)`

gives the desired behaviour and treats `x`

and `y`

in the same manner.

I am surprised that such a basic question doesn’t seem to have an immediate answer in python.

It seems to me that nearly all proposed answers use some kind of type

checking, that is usually not advised in python and they seem restricted to a specific case (they fail with different numerical types or generic iteratable objects that are not tuples or lists).

For me, what works better is importing numpy and using array.size, for example:

```
>>> a=1
>>> np.array(a)
Out[1]: array(1)
>>> np.array(a).size
Out[2]: 1
>>> np.array([1,2]).size
Out[3]: 2
>>> np.array('125')
Out[4]: 1
```

Note also:

```
>>> len(np.array([1,2]))
Out[5]: 2
```

but:

```
>>> len(np.array(a))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-40-f5055b93f729> in <module>()
----> 1 len(np.array(a))
TypeError: len() of unsized object
```

Is there an equivalent to isscalar() in numpy? Yes.

```
>>> np.isscalar(3.1)
True
>>> np.isscalar([3.1])
False
>>> np.isscalar(False)
True
>>> np.isscalar('abcd')
True
```

Simply use `size`

instead of `len`

!

```
>>> from numpy import size
>>> N = [2, 3, 5]
>>> size(N)
3
>>> N = array([2, 3, 5])
>>> size(N)
3
>>> P = 5
>>> size(P)
1
```

Here is the best approach I have found: Check existence of `__len__`

and `__getitem__`

.

You may ask why? The reasons includes:

- The popular method
`isinstance(obj, abc.Sequence)`

fails on some objects including PyTorch’s Tensor because they do not implement`__contains__`

. - Unfortunately, there is nothing in Python’s collections.abc that checks for only
`__len__`

and`__getitem__`

which I feel are minimal methods for array-like objects. - It works on list, tuple, ndarray, Tensor etc.

So without further ado:

```
def is_array_like(obj, string_is_array=False, tuple_is_array=True):
result = hasattr(obj, "__len__") and hasattr(obj, '__getitem__')
if result and not string_is_array and isinstance(obj, (str, abc.ByteString)):
result = False
if result and not tuple_is_array and isinstance(obj, tuple):
result = False
return result
```

Note that I’ve added default parameters because most of the time you might want to consider strings as values, not arrays. Similarly for tuples.

preds_test[0] is of shape (128,128,1)

Lets check its data type using isinstance() function

isinstance takes 2 arguments.

1st argument is data

2nd argument is data type

isinstance(preds_test[0], np.ndarray) gives Output as True. It means preds_test[0] is an array.

To answer the question in the title, a direct way to tell if a variable is a scalar is to try to convert it to a float. If you get `TypeError`

, it’s not.

```
N = [1, 2, 3]
try:
float(N)
except TypeError:
print('it is not a scalar')
else:
print('it is a scalar')
```

Since the general guideline in Python is to ask for forgiveness rather than permission, I think the most pythonic way to detect a string/scalar from a sequence is to check if it contains an integer:

```
try:
1 in a
print('{} is a sequence'.format(a))
except TypeError:
print('{} is a scalar or string'.format(a))
```