How to write conditional code that's compatible with both plain Python values and NumPy arrays?
<p>For writing âpiecewise functionsâ in Python, I'd normally use <code>if</code> (in either the control-flow or ternary-operator form).</p>

<pre><code>def spam(x):
    return x+1 if x&gt;=0 else 1/(1-x)
</code></pre>

<p>Now, with NumPy, the mantra is to avoid working on single values in favour of vectorisation, for performance. So I reckon something like this would be preferred:<sub><em>As Leon remarks, the following is <strong>wrong</strong></em></sub></p>

<pre><code>def eggs(x):
    y = np.zeros_like(x)
    positive = x&gt;=0
    y[positive] = x+1
    y[np.logical_not(positive)] = 1/(1-x)
    return y
</code></pre>

<p>(Correct me if I've missed something here, because frankly I find this very ugly.)</p>

<p>Now, of course <code>eggs</code> will <em>only</em> work if <code>x</code> is actually a NumPy array, because otherwise <code>x&gt;=0</code> simply yields a single boolean, which can't be used for indexing (at least doesn't do the right thing).</p>

<p>Is there a good way to write code that looks more like <code>spam</code> but works idiomatic on Numpy arrays, or should I just use <code>vectorize(spam)</code>?</p>

<p>Use <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html" rel="nofollow"><code>np.where</code></a>. You'll get an array as the output even for plain number input, though.</p>

<pre><code>def eggs(x):
    y = np.asarray(x)
    return np.where(y&gt;=0, y+1, 1/(1-y))
</code></pre>

<p>This works for both arrays and plain numbers:</p>

<pre><code>&gt;&gt;&gt; eggs(5)
array(6.0)
&gt;&gt;&gt; eggs(-3)
array(0.25)
&gt;&gt;&gt; eggs(np.arange(-3, 3))
/home/praveen/.virtualenvs/numpy3-mkl/bin/ipython3:2: RuntimeWarning: divide by zero encountered in true_divide
array([ 0.25      ,  0.33333333,  0.5       ,  1.        ,  2.        ,  3.        ])
&gt;&gt;&gt; eggs(1)
/home/praveen/.virtualenvs/numpy3-mkl/bin/ipython3:3: RuntimeWarning: divide by zero encountered in long_scalars
  # -*- coding: utf-8 -*-
array(2.0)
</code></pre>

<p>As ayhan remarks, this raises a warning, since <code>1/(1-x)</code> gets evaluated for the whole range. But a warning is just that: a warning. If you know what you're doing, you can ignore the warning. In this case, you're only choosing <code>1/(1-x)</code> from indices where it can never be <code>inf</code>, so you're safe.</p>

python arrays numpy vectorization