<p dir="auto">It seems that whitespace in a character array is treated as if it is zero. An example of this is shown below with details about the environment. This seems to match up with how character arrays work. Still this seems a bit surprising from a Python perspective. Am trying to understand if this is intentional and also if there is an builtin element-wise operator that we can use to reproduce this behavior.</p>
<p dir="auto">Code snippet:</p>
<details>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [1]: import numpy as np

In [2]: s = np.array(list(&quot;hello world&quot;))

In [3]: s
Out[3]: 
array(['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'],
      dtype='|S1')

In [4]: s.nonzero()
Out[4]: (array([ 0,  1,  2,  3,  4,  6,  7,  8,  9, 10]),)"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">1</span>]: <span class="pl-s1">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>

<span class="pl-v">In</span> [<span class="pl-c1">2</span>]: <span class="pl-s1">s</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-en">list</span>(<span class="pl-s">"hello world"</span>))

<span class="pl-v">In</span> [<span class="pl-c1">3</span>]: <span class="pl-s1">s</span>
<span class="pl-v">Out</span>[<span class="pl-c1">3</span>]: 
<span class="pl-en">array</span>([<span class="pl-s">'h'</span>, <span class="pl-s">'e'</span>, <span class="pl-s">'l'</span>, <span class="pl-s">'l'</span>, <span class="pl-s">'o'</span>, <span class="pl-s">' '</span>, <span class="pl-s">'w'</span>, <span class="pl-s">'o'</span>, <span class="pl-s">'r'</span>, <span class="pl-s">'l'</span>, <span class="pl-s">'d'</span>],
      <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'|S1'</span>)

<span class="pl-v">In</span> [<span class="pl-c1">4</span>]: <span class="pl-s1">s</span>.<span class="pl-en">nonzero</span>()
<span class="pl-v">Out</span>[<span class="pl-c1">4</span>]: (<span class="pl-en">array</span>([ <span class="pl-c1">0</span>,  <span class="pl-c1">1</span>,  <span class="pl-c1">2</span>,  <span class="pl-c1">3</span>,  <span class="pl-c1">4</span>,  <span class="pl-c1">6</span>,  <span class="pl-c1">7</span>,  <span class="pl-c1">8</span>,  <span class="pl-c1">9</span>, <span class="pl-c1">10</span>]),)</pre></div>
</details>
<br>
Environment:
<br>
<br>
<details>
<div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="name: np2
channels:
- conda-forge
- defaults
dependencies:
- appnope=0.1.0=py27_0
- backports.shutil_get_terminal_size=1.0.0=py27_1
- blas=1.1=openblas
- ca-certificates=2017.4.17=0
- certifi=2017.4.17=py27_0
- decorator=4.1.1=py27_0
- enum34=1.1.6=py27_1
- ipython=5.4.1=py27_0
- ipython_genutils=0.2.0=py27_0
- libgfortran=3.0.0=0
- ncurses=5.9=10
- numpy=1.13.1=py27_blas_openblas_200
- openblas=0.2.19=2
- openssl=1.0.2l=0
- pathlib2=2.3.0=py27_0
- pexpect=4.2.1=py27_0
- pickleshare=0.7.3=py27_0
- pip=9.0.1=py27_0
- prompt_toolkit=1.0.14=py27_0
- ptyprocess=0.5.2=py27_0
- pygments=2.2.0=py27_0
- python=2.7.13=1
- readline=6.2=0
- scandir=1.5=py27_1
- setuptools=36.2.2=py27_0
- simplegeneric=0.8.1=py27_0
- six=1.10.0=py27_1
- sqlite=3.13.0=1
- tk=8.5.19=1
- traitlets=4.3.2=py27_0
- wcwidth=0.1.7=py27_0
- wheel=0.29.0=py27_0
- zlib=1.2.11=0
- pip:
  - backports.shutil-get-terminal-size==1.0.0
  - ipython-genutils==0.2.0
  - prompt-toolkit==1.0.14"><pre class="notranslate"><span class="pl-ent">name</span>: <span class="pl-s">np2</span>
<span class="pl-ent">channels</span>:
- <span class="pl-s">conda-forge</span>
- <span class="pl-s">defaults</span>
<span class="pl-ent">dependencies</span>:
- <span class="pl-s">appnope=0.1.0=py27_0</span>
- <span class="pl-s">backports.shutil_get_terminal_size=1.0.0=py27_1</span>
- <span class="pl-s">blas=1.1=openblas</span>
- <span class="pl-s">ca-certificates=2017.4.17=0</span>
- <span class="pl-s">certifi=2017.4.17=py27_0</span>
- <span class="pl-s">decorator=4.1.1=py27_0</span>
- <span class="pl-s">enum34=1.1.6=py27_1</span>
- <span class="pl-s">ipython=5.4.1=py27_0</span>
- <span class="pl-s">ipython_genutils=0.2.0=py27_0</span>
- <span class="pl-s">libgfortran=3.0.0=0</span>
- <span class="pl-s">ncurses=5.9=10</span>
- <span class="pl-s">numpy=1.13.1=py27_blas_openblas_200</span>
- <span class="pl-s">openblas=0.2.19=2</span>
- <span class="pl-s">openssl=1.0.2l=0</span>
- <span class="pl-s">pathlib2=2.3.0=py27_0</span>
- <span class="pl-s">pexpect=4.2.1=py27_0</span>
- <span class="pl-s">pickleshare=0.7.3=py27_0</span>
- <span class="pl-s">pip=9.0.1=py27_0</span>
- <span class="pl-s">prompt_toolkit=1.0.14=py27_0</span>
- <span class="pl-s">ptyprocess=0.5.2=py27_0</span>
- <span class="pl-s">pygments=2.2.0=py27_0</span>
- <span class="pl-s">python=2.7.13=1</span>
- <span class="pl-s">readline=6.2=0</span>
- <span class="pl-s">scandir=1.5=py27_1</span>
- <span class="pl-s">setuptools=36.2.2=py27_0</span>
- <span class="pl-s">simplegeneric=0.8.1=py27_0</span>
- <span class="pl-s">six=1.10.0=py27_1</span>
- <span class="pl-s">sqlite=3.13.0=1</span>
- <span class="pl-s">tk=8.5.19=1</span>
- <span class="pl-s">traitlets=4.3.2=py27_0</span>
- <span class="pl-s">wcwidth=0.1.7=py27_0</span>
- <span class="pl-s">wheel=0.29.0=py27_0</span>
- <span class="pl-s">zlib=1.2.11=0</span>
- <span class="pl-ent">pip</span>:
  - <span class="pl-s">backports.shutil-get-terminal-size==1.0.0</span>
  - <span class="pl-s">ipython-genutils==0.2.0</span>
  - <span class="pl-s">prompt-toolkit==1.0.14</span></pre></div></details>
<p dir="auto">The following table shows the extents of the problem</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="x : str
sc = np.str_(x)
arr = np.array(x, np.str_)"><pre class="notranslate"><span class="pl-s1">x</span> : <span class="pl-s1">str</span>
<span class="pl-s1">sc</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">str_</span>(<span class="pl-s1">x</span>)
<span class="pl-s1">arr</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-s1">x</span>, <span class="pl-s1">np</span>.<span class="pl-s1">str_</span>)</pre></div>
<table role="table">
<thead>
<tr>
<th><code class="notranslate">x</code></th>
<th><code class="notranslate">bool(x)</code></th>
<th><code class="notranslate">bool(sc)</code></th>
<th><code class="notranslate">bool(arr[()])</code></th>
<th><code class="notranslate">bool(arr)</code></th>
<th><code class="notranslate">sc.astype(bool)</code></th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="notranslate">''</code></td>
<td><code class="notranslate">False</code></td>
<td><code class="notranslate">False</code></td>
<td><code class="notranslate">False</code></td>
<td><code class="notranslate">False</code></td>
<td><code class="notranslate">ValueError</code></td>
</tr>
<tr>
<td><code class="notranslate">'\0'</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">False</code></td>
<td><code class="notranslate">False</code></td>
<td><code class="notranslate">ValueError</code></td>
</tr>
<tr>
<td><code class="notranslate">' '</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">False</code></td>
<td><code class="notranslate">ValueError</code></td>
</tr>
<tr>
<td><code class="notranslate">' \0'</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">False</code></td>
<td><code class="notranslate">ValueError</code></td>
</tr>
<tr>
<td><code class="notranslate">'0'</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">False</code></td>
</tr>
<tr>
<td><code class="notranslate">'1'</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
</tr>
<tr>
<td><code class="notranslate">'\0 '</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">ValueError</code></td>
</tr>
<tr>
<td><code class="notranslate">' \0 '</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">True</code></td>
<td><code class="notranslate">ValueError</code></td>
</tr>
</tbody>
</table>
 <details>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="def call_or_exc(f):
    try:
        return f()
    except Exception as e:
        return e

def truthiness(x):
    x_arr = np.array(x)
    x_sc = np.unicode_(x)
    x_sc2 = x_arr[()]
    return bool(x), bool(x_sc), bool(x_sc2), bool(x_arr), call_or_exc(lambda: x_sc.astype(bool))

def fmt(x):
    if isinstance(x, str): return repr(x).replace(r'\x00', r'\0')
    if isinstance(x, Exception): return type(x).__name__
    return repr(x)

print(' | '.join(&quot;`{}`&quot;.format(x) for x in ['x', 'bool(x)', 'bool(sc)', 'bool(arr[()])', 'bool(arr)', 'sc.astype(bool)']))
print(' | '.join(['--'] * 6))
for val in ['', '\0', ' ', ' \0', '0', '1', '\0 ', ' \0 ']:
   print(' | '.join(&quot;`{}`&quot;.format(fmt(x)) for x in (val,)+truthiness(val)))"><pre class="notranslate"><span class="pl-k">def</span> <span class="pl-en">call_or_exc</span>(<span class="pl-s1">f</span>):
    <span class="pl-k">try</span>:
        <span class="pl-k">return</span> <span class="pl-en">f</span>()
    <span class="pl-k">except</span> <span class="pl-v">Exception</span> <span class="pl-k">as</span> <span class="pl-s1">e</span>:
        <span class="pl-k">return</span> <span class="pl-s1">e</span>

<span class="pl-k">def</span> <span class="pl-en">truthiness</span>(<span class="pl-s1">x</span>):
    <span class="pl-s1">x_arr</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">array</span>(<span class="pl-s1">x</span>)
    <span class="pl-s1">x_sc</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">unicode_</span>(<span class="pl-s1">x</span>)
    <span class="pl-s1">x_sc2</span> <span class="pl-c1">=</span> <span class="pl-s1">x_arr</span>[()]
    <span class="pl-k">return</span> <span class="pl-en">bool</span>(<span class="pl-s1">x</span>), <span class="pl-en">bool</span>(<span class="pl-s1">x_sc</span>), <span class="pl-en">bool</span>(<span class="pl-s1">x_sc2</span>), <span class="pl-en">bool</span>(<span class="pl-s1">x_arr</span>), <span class="pl-en">call_or_exc</span>(<span class="pl-k">lambda</span>: <span class="pl-s1">x_sc</span>.<span class="pl-en">astype</span>(<span class="pl-s1">bool</span>))

<span class="pl-k">def</span> <span class="pl-en">fmt</span>(<span class="pl-s1">x</span>):
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">x</span>, <span class="pl-s1">str</span>): <span class="pl-k">return</span> <span class="pl-en">repr</span>(<span class="pl-s1">x</span>).<span class="pl-en">replace</span>(<span class="pl-s">r'\x00'</span>, <span class="pl-s">r'\0'</span>)
    <span class="pl-k">if</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">x</span>, <span class="pl-v">Exception</span>): <span class="pl-k">return</span> <span class="pl-en">type</span>(<span class="pl-s1">x</span>).<span class="pl-s1">__name__</span>
    <span class="pl-k">return</span> <span class="pl-en">repr</span>(<span class="pl-s1">x</span>)

<span class="pl-en">print</span>(<span class="pl-s">' | '</span>.<span class="pl-en">join</span>(<span class="pl-s">"`{}`"</span>.<span class="pl-en">format</span>(<span class="pl-s1">x</span>) <span class="pl-k">for</span> <span class="pl-s1">x</span> <span class="pl-c1">in</span> [<span class="pl-s">'x'</span>, <span class="pl-s">'bool(x)'</span>, <span class="pl-s">'bool(sc)'</span>, <span class="pl-s">'bool(arr[()])'</span>, <span class="pl-s">'bool(arr)'</span>, <span class="pl-s">'sc.astype(bool)'</span>]))
<span class="pl-en">print</span>(<span class="pl-s">' | '</span>.<span class="pl-en">join</span>([<span class="pl-s">'--'</span>] <span class="pl-c1">*</span> <span class="pl-c1">6</span>))
<span class="pl-k">for</span> <span class="pl-s1">val</span> <span class="pl-c1">in</span> [<span class="pl-s">''</span>, <span class="pl-s">'\0'</span>, <span class="pl-s">' '</span>, <span class="pl-s">' \0'</span>, <span class="pl-s">'0'</span>, <span class="pl-s">'1'</span>, <span class="pl-s">'\0 '</span>, <span class="pl-s">' \0 '</span>]:
   <span class="pl-en">print</span>(<span class="pl-s">' | '</span>.<span class="pl-en">join</span>(<span class="pl-s">"`{}`"</span>.<span class="pl-en">format</span>(<span class="pl-en">fmt</span>(<span class="pl-s1">x</span>)) <span class="pl-k">for</span> <span class="pl-s1">x</span> <span class="pl-c1">in</span> (<span class="pl-s1">val</span>,)<span class="pl-c1">+</span><span class="pl-en">truthiness</span>(<span class="pl-s1">val</span>)))</pre></div>
<summary>Generated with...</summary>
</details>
<p dir="auto">The differences come down to:</p>
<ul dir="auto">
<li><code class="notranslate">bool(arr[()])</code> - indexing string arrays causes trailing nulls to be truncated. This is unavoidable.</li>
<li><code class="notranslate">bool(arr)</code> - has special handling to treat spaces as falsy. This seems unpythonic, since that's not how <code class="notranslate">str.__bool__</code> behaves - are we stuck with it</li>
<li><code class="notranslate">arr.astype(bool)</code> - treated as <code class="notranslate">arr.astype(int).astype(bool)</code>, which seems bizarre</li>
</ul>