Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

np array as optional arguments

I have a function that can accept two optional np.array as arguments. In case both are passed the function should do perform some task.

def f(some_stuff, this=None, that=None):
    ...do something...
    if this and that:
       perform_the_task()

This works as expected if none of the optional arguments are passed. If I pass a np.array then I obtain the error

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Is there more compact way of checking if the extra args are passed? I guess I can safely assume that if they are passed, then they are going to be np.array.

like image 257
meto Avatar asked Dec 24 '22 12:12

meto


2 Answers

Firstly, you can assume that they will be the right type (especially if you're the only one using the code). Just add it to the documentation. Type checking of arguments Python (the accepted answer even sighs as they explain duck typing)

The exception you're getting is common and is all over SO, like ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().

In your case,

if this is not None and that is not None

will accomplish what you want. The issue is not the "and", so much as the fact that the array

     if np.array([True, False]):
         foo()

is ambiguous from numpy's point of view, in that some of the array's values are true, but not all of them... so what should it return?. This behaviour is notably inconsistent with the behaviour of lists (I believe your current code follows the SO-recommended way of checking if a list is None or empty)

If you're thinking of a Java-esk way of overloading your function depending on how many arguments are passed, you're not thinking pythonically enough. You can certainly send whatever comes after that conditional to another function to "concisely" deal with it. The following would also be fine

def f(some_stuff, this=None, that=None):
    ...do something...

       perform_the_task(this,that)

def perform_the_task(this,that):
    if this is None or that is None: return
    raise NotImplementedException
like image 176
en_Knight Avatar answered Dec 27 '22 01:12

en_Knight


As you can see in the sidebar this ValueError has come up before - many times.

The core of the problem is that numpy arrays can return multiple truth values, while many Python operations expect just one.

I'll illustrate:

In [140]: this=None

In [141]: if this:print 'yes'

In [142]: if this is None: print 'yes'
yes

In [143]: this=np.array([1,2,3])

In [144]: if this: print 'yes'
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

In [145]: if this is None: print 'yes'

In [146]: this and this
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

In [147]: [1,2,3] is None
Out[147]: False
In [148]: this is None
Out[148]: False

In [149]: [1,2,3]==3    # one value
Out[149]: False     
In [150]: this == 3    # multiple values
Out[150]: array([False, False,  True], dtype=bool)

Logical operations like not usually return a simple True/False, but for arrays, they return a value for each element of the array.

In [151]: not [1,2,3]
Out[151]: False

In [152]: not None
Out[152]: True

In [153]: not this
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

In your function, if you don't give f 2 or more arguments, this and that will have value None. The safe way to test that is with is None or is not None:

def f(some_stuff, this=None, that=None):
    ...do something...
    if this is not None and that is not None:
       perform_the_task()
like image 39
hpaulj Avatar answered Dec 27 '22 01:12

hpaulj