My first “real” Python Program pt. 1


Whenever I start learning a new programming language, I like to start off with a project to get used to the syntax of the language without having to deal with finding holes in my logic. Typically, this program has been a simple “Mad-Libs” style program in which I prompt the user for some words and insert them into a (sometimes) hilarious story. For the most part in the past, these have been statically written stories in which I hard code variable names into a string and write custom prompts for each variable. When starting out in Python, I decided this would not be enough of a challenge. Somewhere between PHP and C# in my language path I hit a point where programming started to make sense on a deeper level. Adding new object types to my repertoire was becoming an everyday occurrence, I began branching out from what I had been taught in programming classes, and creating and dealing with objects dynamically in loops without ever knowing their names became the norm, and no longer blew my mind.

I decided it was time to up the ante with Python. Instead of statically creating one or two stories for the user to possibly fill out, I decided to create a framework from which infinite stories could be created and automatically loaded. This would require several things that previous starting programs had not, such as File I/O, a basic method for randomly choosing files from a directory, and the ability to accept a variable number of command-line arguments to allow for the selection of an individual story. This would also require the creation of a tag-based markup system for creating stories, so that the prompt presented to the user could be parsed automatically from a text file written by just about anyone.

I started out with the basics, seeing if I could parse and return a statically written story with a few simple words for replacement and guaranteed hilarity. I figured Sir Mix-A-Lot’s “Baby Got Back” would be a good place to start:

if __name__ == "__main__":
     story = """
I like [adjective] [plural_noun] and I cannot [verb]
You other [plural_noun] can't [verb]
When a [noun] [verb_ending_in_s] in with an [adjective] waist
And a [adjective] thing in your [noun]
You get [past_tense_verb]
     """

As you can see, the tags are simply the type of word you want the user to enter enclosed in square brackets, with the underscore character instead of a space. This is a simple enough system that just about anyone could write stories to be parsed out. After writing the story, the first step is to scan through the story looking for tags. When we find one, we are going to add it to a dictionary by stripping off the brackets, and using what’s left as the dictionary key. In the case of duplicate tags, we simply ignore all but the first. We do this by:

def createDictionaryOfTags(story):
     """Returns a dictionary containing each tag and a list in which to store all variables
     """
     tagDef = re.compile("\[\w*\]")
     tags = tagDef.findall(story)
     tagDict = {}
     for tag in tags:
          value = tag.replace('[', '')
          value = value.replace(']', '')
          if value in tagDict:
               value = value
          else:
               tagDict[value] = "placeholder"
     return tagDict

Note that the value for each key is “placeholder”. We will be changing that shortly to a list containing the results of the user prompts. First, we need to build the user prompts based upon the contents of the tag. Initially, I had written the prompts so that it would say something along the lines of “Please enter a [tagname]:”, but there were some issues with that. First, words that begin with a vowel would look funny as “Please enter a adjective:”, and the second main issue was that during a story where there were (for example) 15 verbs the user would be prompted 15 times in a row with the prompt “Please enter a verb:”. To solve these problems, I added in logic to detect the first letter of the tag name, and changed the “a” to “an” for words that started with a vowel. I also added in a method for counting the number of each type of tag in the story, and added a “(n of total):” to the end of the prompt to give the user an indication of what was to come and what had passed. The code for the above (including actually prompting the user) is here:

def countBlanksOfType(blankType, story):
     """Allows the user to find out how many tags of a certain type are in a story

     Returns int"""    
     tag = "[%s]" % (blankType)
     return story.count(tag)

def buildPromptByTagName(tag):
     tag = tag.replace('[', '')
     tag = tag.replace(']', '')
     vowels = "aeiouAEIOU"
     if tag[0] in vowels:
          prompt = "Please enter an %s" % (tag.replace('_', ' '))
     else:
          prompt = "Please enter a %s" % (tag.replace('_', ' '))
     return prompt

def buildWordList(prompt, number):
    """Allows the user to create a list of words from a custom prompt

    Returns list"""
    words = ["test"]
    try:
        for i in range(0, number):
            if i == 0:
                words.insert(0, raw_input("%s (%d of %d): " % (prompt, i+1, number)))
                words.remove("test")
            else:
                words.append(raw_input("%s (%d of %d): " % (prompt, i+1, number)))
        return words
    except KeyboardInterrupt:
        print "User Cancelled Action"

After storing the user’s input in a Dictionary of Lists, it is time to take the user input and place it back into the story to return to the user:

def replaceBlanksByType(blankType, story, wordList):
    """Allows the user to replace all tags of a certain type with list items from a matching list

    Returns string"""    
    tag = "[%s]" % (blankType)
    for word in wordList:
        story = story.replace(tag, word, 1)
    return story

That basically sums up the functions involved in parsing out the story. Unfortunately, that is where we will stop for now. Until next time, let me know what you think!

Leave a comment

3 Comments

  1. This is good. I would recommend you use one of the free Python books online – you can use it without having to buy a hard copy.

    Good luck

    Reply
  2. Eamon

     /  April 14, 2010

    Thank you very much these tutorials are excellent for beginners.

    Reply
  1. My first “real” Python Program pt. 2 « Brennydoogles' Programming Blog

Leave a comment