Here's the basic version, using `str.isdigit`

In [1]:

```
def count_non_digits(s):
count = 0
for i in range(len(s)):
if not s[i].isdigit():
count = count + 1
return count
```

`str.isdigit`

themselves. This is not necessary, but it's good for practicing

In [2]:

```
def is_str_all_digits(s):
'''
(str->bool)
Return True iff s consists only of digits
(Note: str.digit is a little bit more complext than that)
'''
for i in range(len(s)):
if s[i] not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
#if s[i] not in "0123456789" is more concise and would work as well
return False
return True
```

Here's a slightly more concise version, which uses a new type of loop construct:

In [3]:

```
def count_non_digits(s):
count = 0
for c in s:
if not c.isdigit():
count += 1
return count
```

*indices* inside `s`

(0, 1, 2, ...., `len(s)-1`

), we can loop through the *elements* of `s`

directly. This is preferable in situations where all we ever use the `i`

in `for i in range()`

for is to access the element `s[i]`

.

`passwd`

a valid password?¶This is mostly an exercise in finding the right string methods

In [5]:

```
def password_is_valid(passwd):
""" (str) -> bool
A strong password has a length greater than or equal to 6, contains at
least one lowercase letter, at least one uppercase letter, and at least
one digit. Return True iff passwd is considered strong.
>>> check_password(’I<3csc108’)
True
"""
if len(passwd) < 6:
return False
#First, set up variables that tell us whether we've encountered
#a lowercase letter, and uppercase letter, or a digit
#Initially, they are all set to False
has_lowercase = False
has_uppercase = False
has_digit = False
for c in passwd:
if c.isupper(): #Note: blah == (blah == True), so there's no point to going
#c.isupper() == True instead
has_uppercase = True
elif c.islower():
has_lowercase = True
elif c.isdigit():
has_digit = True
#Now, return True if all three are True
#(i.e., has_lowercase is True, *and* has_uppercase is True, *and* has_digit is True)
return has_lowercase and has_uppercase and has_digit
```

Here, we just need to keep checking whether the number is even until we encounter an even number, and then return. To check whether a number `n`

is even, we can check whether `n % 2`

(the remainder of the division of `n`

by 2) is even. If we haven't returned inside the for-loop where we keep checking for evenness, we return `-1`

.

In [6]:

```
def first_even(items):
""" (list of int) -> int
Return the first even number from items. Return -1 if items contains no even numbers.
>>> first_even([5, 8, 3, 2])
8
>>> first_even([7, 1])
-1
"""
for n in items:
if n % 2 == 0:
return n
return -1
```

Let's try something concise, using str.islower and the `in`

operator

In [7]:

```
def is_vowel(c):
return c.lower() in "aeiou"
```

Let's build up the disemvowelled version of a string by first initializing the result to `""`

, and then adding in all the non-vowels

In [8]:

```
def disemvowel(s):
#dsmvwl = "" #too funny of a name... Let's just go wih res
res = ""
for c in s:
if not is_vowel(c):
res += c #the same as: res = res + c
return res
```

In [9]:

```
def reverse_str(s):
'''return the reversed version of s
reverse_str("abc") -> "cba"
'''
res = ""
for c in s:
res = c + res
return res
```