Count Even Digits In Number I was asked to complete this CodeStepByStep problem. Here's a quick summary:


  Write a function named count_even_digits that accepts two integers as
  parameters and returns the number of even-valued digits in the first
  number. An even-valued digit is either 0, 2, 4, 6, or 8. The second
  value represents how many digits the number has. The second value is
  guaranteed to match the number of digits in the first number.
  
  For example, the number 8546587 has four even digits (the two 8s, the
  4, and the 6), so the call count_even_digits(8346387, 7) should return
  4.
  
  You may assume that the values passed to your function are
  non-negative.


My implementation:

def count_even_digits(digit, nums):
    count = 0
    digits = str(digit)
    for i in range(nums):
        if int(digits[i]) % 2 == 0:
            count += 1

    return count


I'm looking for any feedback on my implementation, and how to make this code more efficient. It seems weird that I have to cast the num to a string, then look at each char, convert it to int, then determine if it's even. Having to cast (int =&gt; string =&gt; analyzing as char =&gt; int) seems unnecessary to me.
You should have a look at Loop like a native!. Explicitly iterating over the indices is usually not the best way to do something in Python. By directly iterating over the string representation of n you won't even need the second argument (and you should remove it if the assignment/defined interface would not require it). This will help you a lot later, when you start using generators or other iterables which are not indexable.

In addition, you can use the built-in sum together with the fact that bools are integers with True == 1 and False == 0 and a generator expression to make your function a lot shorter:

def count_even_digits(n, n_digits):
    """Return the number of digits of n which are even.
    Second argument (number of digits) is unused.
    """
    return sum(int(d) % 2 == 0 for d in str(n))


I also added a docstring describing what the function does.



An alternative that does not use the casting to str is to make a digits function:

def digits(n):
    """Yields the digits of `n`, from smallest to largest."""
    while n &gt; 10:
        n, d = divmod(n, 10)
        yield d
    yield n

def count_even_digits2(n, n_digits):
    return sum(d % 2 == 0 for d in digits(n))




Timing wise, these two solutions are both very fast, but the conversion to str stays faster, now tested up to 10**308. I also added the functions shown in the answer by @vurmux and the answer by @spyr03, which are even faster than these two solutions:



Interestingly the manual for loop is faster than the generator expression with sum.



For numbers with a lot of digits, it becomes a bit more complicated. This includes a function proposed in an answer to my question on SO about why the for loop is better than the sum. This function is even faster, but I would only recommend using it if you need that last bit of speed.

def count_even_digits_count_unrolled(n):
    s = str(n)
    return s.count("0") + s.count("2") + s.count("4") + s.count("6") + s.count("8")