def _lazywhere(cond, arrays, f, fillvalue=None, f2=None):
if fillvalue is None:<EOL><INDENT>if f2 is None:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>else:<EOL><INDENT>fillvalue = np.nan<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if f2 is not None:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT><DEDENT>arrays = np.broadcast_arrays(*arrays)<EOL>temp = tuple(np.extract(cond, arr) for arr in arrays)<EOL>out = valarray(shape(arrays[<NUM_LIT:0>]), value=fillvalue)<EOL>np.place(out, cond, f(*temp))<EOL>if f2 is not None:<EOL><INDENT>temp = tuple(np.extract(~cond, arr) for arr in arrays)<EOL>np.place(out, ~cond, f2(*temp))<EOL><DEDENT>return out<EOL>
np.where(cond, x, fillvalue) always evaluates x even where cond is False.
This one only evaluates f(arr1[cond], arr2[cond], ...).
For example,
>>> a, b = np.array([1, 2, 3, 4]), np.array([5, 6, 7, 8])
>>> def f(a, b):
    return a*b
>>> _lazywhere(a > 2, (a, b), f, np.nan)
array([ nan,  nan,  21.,  32.])

Notice it assumes that all `arrays` are of the same shape, or can be
broadcasted together.