164

I'd like to check if variable is None or numpy.array. I've implemented check_a function to do this.

def check_a(a):
    if not a:
        print "please initialize a"

a = None
check_a(a)
a = np.array([1,2])
check_a(a)

But, this code raises ValueError. What is the straight forward way?

ValueError                                Traceback (most recent call last)
<ipython-input-41-0201c81c185e> in <module>()
      6 check_a(a)
      7 a = np.array([1,2])
----> 8 check_a(a)

<ipython-input-41-0201c81c185e> in check_a(a)
      1 def check_a(a):
----> 2     if not a:
      3         print "please initialize a"
      4 
      5 a = None

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
nbro
  • 15,395
  • 32
  • 113
  • 196
Light Yagmi
  • 5,085
  • 12
  • 43
  • 64
  • 3
    This `ValueError` is one of the most common `numpy` questions. It means `not a` produces a boolean array, with (in this case) 2 values. This boolean array cannot be used as an `if` condition! The `is None` alternative is good to know, but you should also understand this error. – hpaulj Apr 22 '16 at 05:01
  • @hpaulj: Not quite - you can't overload `not`, so the error actually happens when `not` tries to treat the array as a single boolean and finds out it can't. If it had been `~a`, that would have used NumPy's overload and failed when `if` tries to use the negated array as a single boolean. – user2357112 Apr 19 '19 at 22:41

2 Answers2

271

Using not a to test whether a is None assumes that the other possible values of a have a truth value of True. However, most NumPy arrays don't have a truth value at all, and not cannot be applied to them.

If you want to test whether an object is None, the most general, reliable way is to literally use an is check against None:

if a is None:
    ...
else:
    ...

This doesn't depend on objects having a truth value, so it works with NumPy arrays.

Note that the test has to be is, not ==. is is an object identity test. == is whatever the arguments say it is, and NumPy arrays say it's a broadcasted elementwise equality comparison, producing a boolean array:

>>> a = numpy.arange(5)
>>> a == None
array([False, False, False, False, False])
>>> if a == None:
...     pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous.
 Use a.any() or a.all()

On the other side of things, if you want to test whether an object is a NumPy array, you can test its type:

# Careful - the type is np.ndarray, not np.array. np.array is a factory function.
if type(a) is np.ndarray:
    ...
else:
    ...

You can also use isinstance, which will also return True for subclasses of that type (if that is what you want). Considering how terrible and incompatible np.matrix is, you may not actually want this:

# Again, ndarray, not array, because array is a factory function.
if isinstance(a, np.ndarray):
    ...
else:
    ...    
user2357112
  • 260,549
  • 28
  • 431
  • 505
Jerfov2
  • 5,264
  • 5
  • 30
  • 52
  • 6
    which do you recommend is the "best" solution? – Monica Heddneck Feb 10 '19 at 22:55
  • 1
    Thanks! The `isinstance(a, np.ndarray)` way looks cleanest to me. The company I recently joined does the `is not None` check and it makes my pythonic alarms blare every time I read it. – Maitreya Jan 05 '21 at 19:44
-1

To stick to == without consideration of the other type, the following is also possible.
type(a) == type(None)

SKO
  • 32
  • 5