you can only compare like terms: numbers with numbers, strings with strings

definite loops iterate across an entire string

indefinite loops need not iterate across an entire string

consider:

```
def mystery1(s, x):
p = -1
i = 0
for c in s:
if p == -1 and c == x:
p = i
i += 1
return p
```

If we are counting, where would we have stopped if we find
`x`

? `p`

stays at `-1`

if the if
statement is never executed

consider

```
def mystery2(m):
d = 0
n = m
while n > 0:
r = n % 10
if r > d:
d = r
n = n // 10
return d
```

idiom of using integer division and remainder dividng by 10 to find digits of a number

the function returns the largest digit that occurs in
`m`

function shows how to iterate through a sequence and remember some piece of information

finds the largest thing, which could be useful in the future

now consider:

```
def is_upper(ch):
b = len(ch) == 1 and 'A' <= ch and ch <= 'Z'
return b
def is_all_upper(s):
if len(s) > 0:
b = True
for c in s:
b = b and is_upper(c)
else:
b = False
return b
```

in `is_all_upper`

, once `b`

becomes False it
will stay that way, but loop will keep going

we would like to use an *indefinite* loop here, but we don’t
(yet) know how to access the individual characters in a string without
using `for`

also note, though, that we can use one function
(`is_upper`

) to help define another
(`is_all_upper`

)

here is another example, to avoid “reinventing the wheel”:

```
def smallest_factor(m):
d = 2
while m % d != 0:
d += 1
return d
def is_prime(m):
b = smallest_factor(m) == m
return b
```

General notion of what’s in a computer’s memory:

Think of a computer’s memory as consecutively addressed collection of fixed sized boxes Computers have billions of units of storage, and each box has its own numerical address

```
'Enigma' stored as:
'E' 'n' 'i' 'g' 'm' 'a'
0 1 2 3 4 5
```

**Subscripting**: indicating which position of a
sequence we are referring to:

`<exp> [ <exp> ]`

Second `<exp>`

is an integer that is
`>= 0`

and `< len(string)`

```
for c in s:
...
```

equivalent to:

```
for i in range(len(s)):
c = s[i]
...
```

equivalent to:

```
i = 0
while i < len(s):
c = s[i]
...
i += 1
```

but this shows that we can write loops that iterate over only
*part* of a string:

```
def substring(s, starting_index, n):
"""Return n characters from s starting at starting_index."""
t = ''
for i in range(n):
t += s[starting_index + i]
return t
```