That’s right. Some day you will code without using your hands:) Photo courtesy of Lovely Bicycle (http://lovelybike.blogspot.com/2012/01/bikes-balance-and-riding-no-hands.html).

A little over a week ago, I was an instructor at a Girl Develop It Philly intro to Python workshop. I was hoping to give a short talk on ‘Thinking Like a Programmer’ but we were having too much fun with projects. Others have found this talk helpful when I have given it in the past, so I’ve made it a blog post.

When I was first learning how to code, I would get frustrated because I could do something on paper and just couldn’t see how to turn it into a program. It would actually keep me up at night. To make your learning process easier, I thought I would demonstrate how to translate an idea into Python code. This tutorial will hopefully help you to start thinking like a programmer.

My undergrad was in English literature and I still love word games:) For our sample project, let’s make a Mad Lib program and, to keep things spicy, let’s use haikus for the sentences.

But First, a Little Background . . .

A haiku is a poem with a five syllable line, a seven syllable line, and a five syllable line. This is one of my favorites:

Haikus are easy,
but sometimes they don’t make sense,
refrigerator.

If you weren’t lucky enough to grow up playing Mad Libs on long car trips, here is a quick primer: the questioner can see the Mad Lib and uses cues in the Mad Lib to prompt the player. The player’s answers are used to complete the Mad Lib, often resulting in a nonsense passage. We want our program to play the questioner and prompt us to fill out the Mad Lib. Game play should look something like this:

Enter a two syllable adjective: fluffy
Enter a one syllable noun: rock
Enter a five syllable noun: observatory

Haikus are fluffy, but sometimes they don't make rock, observatory

The Requirements

OK, so we know how the game should be played. Let’s think about some requirements. Since filling in the same Mad Lib over and over would be pretty boring, let’s make our program choose from multiple haikus. Our list of program requirements should look something like this:

  • Knows several haikus
  • Picks a haiku at random
  • Asks the player for a response
  • Prints the filled out haiku
  • Hilarity ensues!

Great, Now What?

Whenever I am trying to convert something from paper into a program, I like to talk my way through it. So, here I would start with the first requirement. I need to store several haikus in the program — this sounds like a data structure. A data structure is container for your data and each kind of data structure has unique properties.

Yep, that’s really Dr.Dave. It’s also a fantastic photoshop job. Photo courtesy of Greg Smith.

When I was in school learning how to program, I had this great professor, Dr. Dave. Aside from being deeply talented and kind, Dr.Dave was always coming up with pithy statements. This is one of my favorites:

“Pick the right data structure and you have solved half of your problem.”

This feels very true. If I can figure out which data structure to use, I will likely also create a plan for playing the game.

Data structures are like the containers I use for packing my lunch; the structure needs to meet the needs of the content. I have plastic bags, boxes, and containers with a screw-on top for packing my lunch. I could take soup to work in any of these containers, but the container with the screw-on top suits soup best because it is less likely to leak or puncture. Data structures work the same way. Each structure has different characteristics and we need to pick one that suits our data and what we want to do with it. So, let’s describe our data. This should help us figure out which data structure to use.

If I think back to Mad Libs, they are really two things: a sentence with holes and information about those holes.

Haikus are (two syllable adjective),
but sometimes they don’t make (one syllable noun),
(five syllable noun)

This sounds like I’ll need to bundle together sentences and cues, making sure to link the cues with the holes in the sentences. Well, the cues should be easy to tackle. That could just be a list. The sentence could be a string. I’ll place a marker in the sentence for the holes and name the markers so they coordinate with the index value of the cues in the list.

Now I need to pick a data structure to contain these two pieces. Well, since we started by putting our cues in a list, why not bundle the sentence and list of cues into another list? We can put all of our sentence/cue pairs into another list, then randomly pick a sentence/cue pair from the list of Mad Libs.

Solution with Lists

import random

MAD_LIB_0 = ["Haikus are WORD#0, but sometimes they don't make WORD#1, WORD#2",
            ["a two syllable adjective", "a one syllable noun", "a five syllable noun"]]

MAD_LIB_1 = ["Out of WORD#0, We wish to WORD#1 the whole WORD#2, But we never will.",
            ["a three syllable noun", "a one syllable verb", "a one syllable noun"]]

MAD_LIB_2 = ["Lightening WORD#0 -- what I thought were WORD#1, are plumes of pampas grass",
            ["a one syllable verb", "a two syllable plural noun"]]

all_mad_libs = [MAD_LIB_0, MAD_LIB_1, MAD_LIB_2]
mad_lib = random.choice(all_mad_libs)

haiku = mad_lib[0]
cues_for_reader = mad_lib[1]

for index in range(len(cues_for_reader)):
    response = raw_input("Enter " + cues_for_reader[index] + ": ")
    haiku = haiku.replace("WORD#" + str(index), response.strip())

print haiku

Here’s a simplified version of our data structures:

all_mad_libs = list [ list bundle [ string sentence, list [ cues ] ] ]

This seems like a reasonable solution. Once I have picked a sentence/cue pair, I break the pair apart into a sentence and a list of queues. I then loop over the list of cues. For each cue, I ask the user for some input. The user’s response is then placed into the string in the hole that matches the cue’s index value.

But, what if the requirements changed?

Let’s say, rather than pick one haiku at random, we wanted to run through all haikus in order. This sounds like our data structure needs to be iterable — we need to be able to look at each sentence/cue pair one after another. This solution would work well, since lists are easy to iterate over in order. You’ve actually already seen an example of list iteration; we looped or iterated over the list of cues in order.

What if I wanted to store all completed haikus inside our data structure and print them out after the user has completed all of them? This sounds like a question about our data structure’s mutability. Mutability means whether or not we can modify the data in the data structure. Yep, lists are mutable so this implementation offers us some flexibility if our requirements change.

Let’s look at another data structure.

Solution with Tuples

import random
 
MAD_LIB_0 = ("Haikus are WORD#0, but sometimes they don't make WORD#1, WORD#2",
            ["a two syllable adjective", "a one syllable noun", "a five syllable noun"])
 
MAD_LIB_1 = ("Out of WORD#0, We wish to WORD#1 the whole WORD#2, But we never will.",
            ["a three syllable noun", "a one syllable verb", "a one syllable noun"])
 
MAD_LIB_2 = ("Lightening WORD#0 -- what I thought were WORD#1, are plumes of pampas grass",
            ["a one syllable verb", "a two syllable plural noun"])
 
all_mad_libs = [MAD_LIB_0, MAD_LIB_1, MAD_LIB_2]
mad_lib = random.choice(all_mad_libs)

haiku = mad_lib[0]
cues_for_reader = mad_lib[1]
 
for index in range(len(cues_for_reader)):
    response = raw_input("Enter " + cues_for_reader[index] + ": ")
    haiku = haiku.replace("WORD#" + str(index), response.strip())
 
print haiku

Here’s a simplified version of this data structures:

all_mad_libs = list [ tuple bundle ( string sentence, list [ cues ] ) ]

It looks almost identical to the last implementation, but it’s actually quite different. Here we use a structure called a tuple. Tuples are immutable, meaning they can’t be changed.

So, what if the requirements changed?

It would be no problem if we wanted to go through all haikus in order — the tuples are all inside an iterable list. The real problem would happen if we wanted to print out all of the haikus after all cues have been answered. Since tuples are immutable, we could not store the completed haiku inside our existing tuples.

Let’s look at another solution.

Solution with Dictionary

import random

ALL_MAD_LIBS = {"Haikus are WORD#0, but sometimes they don't make WORD#1, WORD#2" :
                ["a two syllable adjective", "a one syllable noun", "a five syllable noun"],

                "Out of WORD#0, We wish to WORD#1 the whole WORD#2, But we never will." :
                ["a three syllable noun", "a one syllable verb", "a one syllable noun"],

                "Lightening WORD#0 -- what I thought were WORD#1, are plumes of pampas grass" :
                ["a one syllable verb", "a two syllable plural noun"]}

all_strings = ALL_MAD_LIBS.keys()

haiku = random.choice(all_strings)
cues_for_reader = all_mad_libs[haiku]

for index in range(len(cues_for_reader)):
    response = raw_input("Enter " + cues_for_reader[index] + ": ")
    haiku = haiku.replace("WORD#" + str(index), response.strip())

print haiku

Here’s a simplified version of this solution:

all_mad_libs = dict { string sentence : list [ cues ] }

This one is really different from all of the other solutions we have seen. Here we are using a dictionary data structure. Python dictionaries work just like paper dictionaries. You use the key (or word) to look up the value (or definition). Dictionaries are an unordered collection of key/value pairs used for lookup. In this solution, we pick a sentence key at random. We then use that key to look up the cues value.

What if the requirements changed?

If we wanted to go through all of haikus in order, we’d be out of luck. Dictionaries are iterable, so we would complete all of the haikus. However, since dictionaries are an unordered collection, there is no guarantee on the order in which we would fill out the haikus.

If I wanted to store each haiku in the data structure as I answered cues, I could do that here with a little dictionary magic. Dictionaries require that all keys be unique and immutable. That means that we have to remove the sentence/cue pair and replace it with a completed sentence/cue pair. Here’s how we’d do that:

dict_of_mad_libs[ completed sentence ] = dict_of_mad_libs.pop( sentence string )

Though this seems pretty fancy, it’s doing something simple. The dict_of_mad_libs.pop( sentence string ) call returns a list of cues after it deletes the sentence/cue pair. We then make a new key/value pair by assigning the list of cues to dict_of_mad_libs[ completed sentence ].

Conclusion

All three of the implementations we have seen meet our current requirements, but we now have a better understanding of the data structures we are using to drive each solution. Also, because we understand data structures, we have a strategy for changing the program should the requirements change.

For my money, I’d pick the dictionary given our current requirements. I find it easier to read and the dictionary avoids the inefficient bundling and unbundling of sentences/cues pairs. Which one would you pick and why? What would a solution using Python sets look like? What are the limitations and advantages of that data structure?

We’ve touched on just a few points of crafting a program, but as you write your own, keep in mind what you’ve learned. Here are some other things to think about as you write your first programs:

  • Readable — have I used good style and naming?
  • Testable — have I kept my methods small and single purpose for easy testing?
  • Efficient — have I used the minimal number of steps to complete the task?
  • Sustainable — what if the requirements changed?

Whew! Thanks for making all the way through this tutorial. Hopefully you’ve learned something from this exercise. Now, get out there and practice making programs:) The only way to be a better programmer is to keep programming! Don’t worry if it feels weird and difficult at first, that’s normal. With practice you’ll find it gets easier to translate ideas into code.

Other Mad Lib Solutions: http://nedbatchelder.com/text/madlibs.html http://codeboom.wordpress.com/2012/11/22/python-madlibs/

More on Crafting Programs: http://natedavisolds.com/blog/2013/02/18/free-style-programming/