for loops over str

We can use loops to repeat a section of code multiple times. The first loop that you will use is a for loop, where we repeat code once for each character in a string.

The general form of a for loop over a string is:

for variable in str:
    body

Now, let's look at an example:

In [3]:
s = 'medicine'
for ch in s:
    print(ch)
m
e
d
i
c
i
n
e

In the code above, ch is a variable name. The first value that ch refers to is the character at index 0 of s, which is 'm'. When the body of the function is reached, ch is printed. Next, the value of ch is changed, so that it refers to the character at index of s, that character is printed, and so on.

Using the Python Visualizer, we can trace this code.

Practice Exercise: Understanding Loops

Modify the code above so that medicine is printed once for each character in the string (instead of the single characters).

Accumulator pattern: numeric accumulator

The letters G, C, A, and T are the four bases that appear in DNA sequences. Write a function that has two parameters representing a DNA sequence and one of the four bases, and return the number of occurences of that base in the sequence. Note: for this problem do not use str.count.

In [10]:
def count_base(dna, base):
    """ (str, str) -> int
    
    Return the number of occurences of base in dna.
    
    >>> count_base('GGTCAG', 'A')
    1    
    >>> count_base('GGTCAGATC', 'G')
    3
    """

To solve this problem, consider how you figured out which values the example function calls should return.

Examine each character in dna.

If that character is base, add one to our total. (The total is our numeric accumulator.)

Once we've examine all characters, return the total.

Now, let's structure this more like code:

For each character in dna
   if the character is equal to base:
       add one to the total
return the total

The description above is called psuedocode. It is an outline of what our code will look like, but it doesn't follow all of the rules of Python syntax. Now, let's write the actual code:

In [11]:
def count_base(dna, base):
    """ (str, str) -> int
    
    Return the number of occurences of base in dna.
    
    >>> count_base('GGTCAG','A')
    1    
    >>> count_base('GGTCAGATC', 'G')
    3
    """
    total = 0
    for letter in dna:
        if letter == base:
            total = total + 1
    return total
In [6]:
count_base('GGTCAG', 'A')
Out[6]:
1
In [12]:
count_base('GGTCAGATC', 'G')
Out[12]:
3

Accumulator pattern: string accumulator

In the previous problem, we looped over the characters of a string and kept a running total. This time, our goal is to loop over the characters of a string and build a new string made up of only the vowels in that string. The new string will initially be empty, we will add vowels as we encounter them, and by the end the string will contain the vowels based on the original string. This is called a string accumulator.

In [ ]:
def collect_vowels(s):
    """ (str) -> str

    Return the vowels from s.  Do not treat the letter
    y as a vowel.

    >>> collect_vowels('Happy Anniversary!')
    'aAiea'
    >>> collect_vowels('xyz')
    ''
    """

    # This is our accumulator variable.  
    # It initially refers to the empty string.
    vowels = ''

    for char in s:
        if char in 'aeiouAEIOU':
            # When we encounter a vowel, concatenate it to vowels.
            vowels = vowels + char  
            
    # After we have passed over every character in s, 
    # return the string that we bulit.
    return vowels

Practice Exercise: count uppercase letters

Define a function named count_upper that has one str parameter and returns the number of uppercase letters in the given string.

In [13]:
def count_upper(s):
    """ (str) -> int
    
    Return the number of uppercase letters in s.
    
    >>> count_upper('abc')
    0
    >>> count_upper('aAbBcC')
    3
    """

Practice Exercise: get uppercase letters

Define a function named get_upper that has one str parameter and returns a string containing the uppercase letters from the given string.

In [14]:
def get_upper(s):
    """ (str) -> str
    
    Return a string containing the uppercase letters in s.
    
    >>> get_upper('abc')
    ''
    >>> get_upper('aAbBcC')
    'ABC'
    
    """

Checking string content

In our next example, we will examine the characters in a string to see if that string is a valid IP address (that is, it contains only digits and periods).

In [15]:
def is_IP_address(address):
    """ (str) -> bool    

    Return True iff address contains only digits and periods.
    
    >>> is_IP_address('128.100.31.52')
    True
    >>> is_IP_address('40 St. George St')
    False
    """

Look at the examples above and consider how you determined whether those two string arguments were valid IP addresses.

For the first string, I examined each character and found them all to be either digits or periods.

However, for the second string, I encountered an 'S' and at that point was able to conclude that the string was not a valid IP address. At that point, I was able to draw my conclusion and stop examining the rest of the string. In other words, if we find a character that is not a digit or period, we can return False.

In [1]:
def is_IP_address(address):
    """ (str) -> bool    

    Return True iff address contains only digits and periods.
    
    >>> is_IP_address('128.100.31.52')
    True
    >>> is_IP_address('40 St. George St')
    False
    """
    
    for ch in address:
        if not ch.isdigit() and ch != '.':
            return False
    return True

Note: be careful not to return True to early. We can only return True once we've examined every character, which is after the for loop has finished executing.