Strings are Lists

Resources

Throughout this course, we’ve seen several different ways to work with strings. In Python, just like in many other programming languages, it is possible to treat strings as a list of individual characters. Because of this, we can write many useful programs that use and manipulate strings in a variety of ways.

Let’s look at one quick example program that can manipulate strings just like a list! Consider the following Python program:

import random
import string


def encode(secret, step):
    output = ""
    for i in secret:
        output = output + i
        for j in step:
            output = output + random.choice(string.ascii_lowercase)
    return output


def decode(code, step):
    return code[::step]


def main():
    secret = input("Enter a secret word")
    step = int(input("Enter a positive integer"))
    code = encode(secret, step)
    print("Your code is:")
    print(code)
    print()
    decoded = decode(code, step)
    print("I can decode it back to:")
    print(decoded)


main()

This is a very simple encoding program that will allow the user to enter a secret phrase, encode it by inserting many random characters between the characters of the word itself, and then show that it can be decoded once again. This is very similar to how a Scytale encodes messages.

Let’s briefly walk through this example using Python Tutor to see how it works. As always, we can copy and paste this code in the tutor.py file in Codio, or click this Python Tutor link to open it in a browser window.

We can skip ahead to the point where the code enters the main function, as shown in this state:

Tutor 7 Tutor 7

Let’s assume that the user inputs the string "password" for the secret word. That will be stored in the secret variable. On the next line, we’ll ask the user to input a positive integer:

Tutor 8 Tutor 8

For this input, we’ll assume the user chooses to input the number $5$. So, we’ll store that in the step variable in our main() function, as shown here:

Tutor 10 Tutor 10

At this point, we’re ready to call the encode() function, which requires two parameters. We’ll use the variables secret and step as the arguments to those parameters, so Python Tutor will create a new frame for the encode() function and store those values within it:

Tutor 12 Tutor 12

At this point, we can notice one very important difference between strings and lists. Even though a string can be treated like a list, as we’ll see in this example program, it is still stored as a single variable item in the frame. So, the encode() function’s frame now contains a copy of the string secret, not a pointer to the original variable in the main() function’s frame. Technically, we would say that strings are an immutable data type, so we cannot change them from within a function like we can do with lists.

Inside of the encode() function, we’ll start by creating a new variable output, which is initially set to store an empty string.

Tutor 13 Tutor 13

Then, we’ll reach a for loop. This for loop will iterate through each character in the secret string, one at a time. So, just like with a list, each character will be stored in the iterator variable i so we can use it inside of our for loop. For the first iteration, we’ll store the character 'p' in the iterator variable i, then we’ll enter the loop:

Tutor 14 Tutor 14

Inside of the loop, the first step is to append the current iterator variable i to the output string. So, we’ll place the character 'p' at the end of that string:

Tutor 15 Tutor 15

Then, we’ll reach a second for loop. This loop will repeat step - 1 times, so we’ll enter the loop and set the iterator variable j to be $0$ initially.

Tutor 16 Tutor 16

Inside of this loop, we have one complex line of code that we haven’t seen before. First, we have the string.ascii_lowercase list, which is a built-in list that is part of the string library which contains all $26$ lowercase letters of the English alphabet. To use this list, we have to include the import string line at the top of our file. Then, we use a special function named random.choice(), which is used to choose a random element from a list. So, we’ll also have to include the import random line at the top of our file to use that library as well. Finally, we’ll add that character to the end of the output string.

Tutor 17 Tutor 17

We’ll repeat this process a few more times. Once we exit the innermost for loop, we should be at this state:

Tutor 24 Tutor 24

In the output variable, we now see the first character of our secret word, 'p', followed by four random characters. These random characters make it more difficult for someone to decode our message. We’ll repeat this process for each of the other letters in our secret word. So, at the end of the encode() function, we should be at this state:

Tutor 102 Tutor 102

As we can see, the output variable appears to be completely random at first glance, which is exactly what we want. At this point, the encode() function will return that string back to the main() function, and it will be stored in the code variable there.

Tutor 104 Tutor 104

Next, the main() function will print out some helpful output, and then eventually it will reach the line that calls the decode() function.

Tutor 107 Tutor 107

Once again, we’ll copy the values in the code and step variables to the decode() function’s frame since they are provided as arguments, and then we’ll enter the decode() function:

Tutor 109 Tutor 109

In this function, we see that we can decode our encoded phrase using a simple slicing operation, with the step variable providing the key we need to get our secret word out of the encoded string. We’ll return that back to the main() function:

Tutor 111 Tutor 111

There we go! We’ve shown that we can easily construct an encoded phrase in a string using a secret word and a step variable, and then we can decode that phrase using a simple string slice. At the same time, we were able to explore how strings can be used like lists by iterating through a string and creating slices of a string, but also that strings are immutable and aren’t passed using call by reference like lists are. Instead, strings use call by value in Python, so we have to remember to return our updated strings at the end of any functions that manipulate them.

Thankfully, being able to work with strings in Python using the same methods as lists makes it very easy to write a wide variety of programs that create and manipulate strings!