how does .isdigit() work in this case?
<p>When I was looking for a solution for the problem "count digits in a given string containing both letters and digits" there was one with built-in function .isdigit(). Here it is:</p>

<pre><code>def count_numbers1(a):
    return sum(int(x) for x in a if x.isdigit())
</code></pre>

<p>It works nicely but I cannot get how it works. I have read that the <code>.isdigit()</code> returns true if there is at least one digit in a string false otherwise. </p>

<p>And one more question: how the function "takes out" the digits from the string and converts it in integers and how it skips the letters? Why <code>int(x)</code> when <code>x</code> is a letter does not produce an error? such as:</p>

<pre><code>&gt;&gt;&gt; int('a')
Traceback (most recent call last):
  File "&lt;pyshell#77&gt;", line 1, in &lt;module&gt;
     int('a')
ValueError: invalid literal for int() with base 10: 'a'
</code></pre>

<p>First of all, the function doesn't <em>count</em> digits in a string. It <em>sums up</em> the digits in a string. Secondly, <code>str.isdigit()</code> only returns true if <strong>all</strong> characters in a string are digits, not just one of the characters. From the <a href="https://docs.python.org/3/library/stdtypes.html#str.isdigit" rel="nofollow"><code>str.isdigit()</code> documentation</a>:</p>

<blockquote>
  <p>Return true if all characters in the string are digits and there is at least one character, false otherwise.</p>
</blockquote>

<p>This means <code>'1a'.isdigit()</code> is false, because there is a non-digit character in that string. Iteration over a string produces 1-character strings, so there is always exactly one character in your function loop.</p>

<p>So, <code>int()</code> is never called on any non-digit, because the <a href="https://docs.python.org/3/tutorial/classes.html#generator-expressions" rel="nofollow">generator expression</a> filters out any character that is not a digit.</p>

<p>You can see what happens if you use a simple <code>for</code> loop instead:</p>

<pre><code>&gt;&gt;&gt; string = 'foo 42 bar 8 1'
&gt;&gt;&gt; for character in string:
...     if character.isdigit():
...         print(character)
...
4
2
8
1
</code></pre>

<p>Because <code>str.isdigit()</code> only returns true for strings (here consisting of just one character each) contains <em>only</em> digits.</p>

<p>Instead of a <code>for</code> loop, you could use a <a href="https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions" rel="nofollow">list comprehension</a> to produce a list:</p>

<pre><code>&gt;&gt;&gt; [c for c in string if c.isdigit()]
['4', '2', '8', '1']
</code></pre>

<p>Now it is easy to add that <code>int()</code> call and see the difference:</p>

<pre><code>&gt;&gt;&gt; [int(c) for c in string if c.isdigit()]
[4, 2, 8, 1]
</code></pre>

<p>Because only digits are passed through, <code>int()</code> always works, it is never called on a letter.</p>

<p>Your function then uses <code>sum()</code> on those values, so for my sample string, adding up 4 + 2 + 8 + 1 is 15:</p>

<pre><code>&gt;&gt;&gt; sum(int(c) for c in string if c.isdigit())
15
</code></pre>

python string sum digits