<p dir="auto">The new <code class="notranslate">heaviside</code> ufunc has the following auto-generated signature both <a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.heaviside.html" rel="nofollow">online</a> and via <code class="notranslate">numpy.info(numpy.heaviside)</code>:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="heaviside(x1, x2, /, out=None, *, where=True, casting='same_kind', order='K', dtype=None, subok=True[, signature, extobj])"><pre class="notranslate"><code class="notranslate">heaviside(x1, x2, /, out=None, *, where=True, casting='same_kind', order='K', dtype=None, subok=True[, signature, extobj])
</code></pre></div>
<p dir="auto">The documentation then goes on discussing the signature in terms of</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="heaviside(x, h0, /, **kwargs)"><pre class="notranslate"><code class="notranslate">heaviside(x, h0, /, **kwargs)
</code></pre></div>
<p dir="auto">so at first glance the mismatch between the variable names <code class="notranslate">x1,x2</code> vs <code class="notranslate">x,h0</code> can be confusing, especially since the former would suggest that the two inputs have similar roles, such as in the case of the inputs of <code class="notranslate">logical_and</code>.</p>
<p dir="auto">After a bit of digging in the source I realized that the auto-generated signature <a href="https://github.com/numpy/numpy/blob/11f3ebf86a16452d0af40b41925b201485ae7f9c/numpy/core/code_generators/generate_umath.py#L561-L566">seems to have the same format as e.g. <code class="notranslate">logical_and</code></a>, and it's likely that the format of the signature can't be further customized, assuming the existing machinery for generating ufuncs. Note that e.g. <a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.logical_and.html" rel="nofollow"><code class="notranslate">logical_and</code></a> which formally shares a signature with <code class="notranslate">heaviside</code> refers to its inputs as <code class="notranslate">x1,x2</code> in the docstring. The same goes for <a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.right_shift.html" rel="nofollow"><code class="notranslate">right_shift</code></a> which again has the same signature, but where the two inputs have similarly asymmetric roles. So perhaps the solution is to keep the auto-generated signature, and adjust the docstring.</p>
<p dir="auto">There's also the minor but independent issue that <a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.heaviside.html" rel="nofollow">the documentation</a> contains the <code class="notranslate">out</code>-<code class="notranslate">where</code>-<code class="notranslate">kwargs</code> lines of the docstring twice (once listed after <code class="notranslate">x</code>, once after <code class="notranslate">h0</code>).</p>
<p dir="auto">Recently updated from numpy 1.11.0 to 1.14.0 and some of my code was immediately broken.</p>
<p dir="auto">You can simulate the broken bits through the following</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="my_metadata_dtype = np.dtype({'names':['Thing1','Thing2'], 
                             'offsets':[22, 40], 
                             'formats':['&gt;u2','&gt;i4'], 
                             'itemsize'=256})
list_of_arrays = [np.arange(i, i+128, dtype='&gt;i2') for i in range(5)]
array_of_metadata = np.array(list_of_arrays, dtype=my_metadata_dtype)
other_array_of_metadata = np.array(list_of_arrays)
other_array_of_metadata.dtype = my_metadata_dtype"><pre class="notranslate"><span class="pl-s1">my_metadata_dtype</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">dtype</span>({<span class="pl-s">'names'</span>:[<span class="pl-s">'Thing1'</span>,<span class="pl-s">'Thing2'</span>], 
                             <span class="pl-s">'offsets'</span>:[<span class="pl-c1">22</span>, <span class="pl-c1">40</span>], 
                             <span class="pl-s">'formats'</span>:[<span class="pl-s">'&gt;u2'</span>,<span class="pl-s">'&gt;i4'</span>], 
                             <span class="pl-s">'itemsize'</span><span class="pl-c1">=</span><span class="pl-c1">256</span>})
<span class="pl-s1">list_of_arrays</span> <span class="pl-c1">=</span> [<span class="pl-s1">np</span>.<span class="pl-en">arange</span>(<span class="pl-s1">i</span>, <span class="pl-s1">i</span><span class="pl-c1">+</span><span class="pl-c1">128</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'&gt;i2'</span>) <span class="pl-k">for</span> <span class="pl-s1">i</span> <span class="pl-c1">in</span> <span class="pl-en">range</span>(<span class="pl-c1">5</span>)]
<span class="pl-s1">array_of_metadata</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-s1">list_of_arrays</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">my_metadata_dtype</span>)
<span class="pl-s1">other_array_of_metadata</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-s1">list_of_arrays</span>)
<span class="pl-s1">other_array_of_metadata</span>.<span class="pl-s1">dtype</span> <span class="pl-c1">=</span> <span class="pl-s1">my_metadata_dtype</span></pre></div>
<p dir="auto">One would expect that array_of_metadata and other_array_of_metadata should be the same thing.<br>
They are not.  I submit that the line creating array_of_metadata is buggy.  I believe this produced the same as the lines that produce other_array_of_metadata in previous versions.</p>
<p dir="auto">But that wasn't even the primary bug I was going to talk about.  I discovered that one while hunting down this one.</p>
<p dir="auto">Take our other_array_of_metadata:<br>
Let's make a new array from a subset of this array (not just a view)</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="sub_array = np.array(other_array_of_metadata[2:4])
sub_array.dtype = '&gt;i2'"><pre class="notranslate"><span class="pl-s1">sub_array</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-s1">other_array_of_metadata</span>[<span class="pl-c1">2</span>:<span class="pl-c1">4</span>])
<span class="pl-s1">sub_array</span>.<span class="pl-s1">dtype</span> <span class="pl-c1">=</span> <span class="pl-s">'&gt;i2'</span></pre></div>
<p dir="auto">You will see that our sub_array now has strange things in the spaces that were not exposed by our dtype.  Not the nice aranges we had constructed before.  In 1.11, this code would have preserved the data that was not exposed.  Now it appears that the unexposed portions of sub-array are never initialized to anything.  This matters because sometimes we want to only expose a part of our metadata to our code, but when we write the metadata back out to disk, want all of it preserved.</p>
<p dir="auto">I can understand making a design choice to not initialize the unexposed portions of a dtype when constructing new elements from literals or from scratch.  But when you already have an element of this dtype, ignoring the empty space seems like an inferior choice.</p>