PROJECT 8

Silly Sentences

In this project you’re going to put together a program that spits out a hilarious mixture of words — sort of like Mad Libs. To do this, you’re going to tackle string formatting for prettier printing.

image

This project’s object is to create templates for words that are randomly chosen from a list. The randomness of the words makes them absurd and, hopefully, funny enough to make you laugh out loud.

To complete this project, you

  1. Read about Python formatting strings.
  2. Create templates for the formatting strings.
  3. Create lists of words to put into the formatting strings.
  4. Choose words at random.
  5. Print the words into the template using formatting.

Insert Format Strings

Format strings let you fit changeable bits of a message into a template. That way it’s easier to present your messages, and it makes your code more readable.

Fire up IDLE. At the interpreter, type the following and be careful — there are two strings. The first is "Hi there %s. You are such a good author." and the second is "Brendan". In between them is the % character.

>>> print("Hi there %s. You are such a good author."%"Brendan")

Hi there Brendan. You are such a good author.

Why, thank you. That’s a very kind thing to say.

Can you see what has happened there? The second string ("Brendan") was substituted into the first string in the place where the %s was.

tip In IDLE, the strings are in green and the %% sign is black.

  • The % sign is called Python’s formatting operator.
  • The string on the right of the % is the formatting value.
  • The string on the left of the % is the format string (or format template).
  • The first string’s %s symbol is called a conversion specifier. (Seriously, I’m not making up these names.)

The specifier in this case (%s) says to convert the formatting value into a string. (s stands for string.) The main specifier you’ll want is %s (that is, convert to a string). A lot of other specifiers exist, but you’ll mainly work with these: integer %i, fixed point %f, general %g, and percent sign %.

tip Making messages according to a template is easier with formatting templates strings. For example, say you want to print out something like “You have 15 turns remaining until the end of the game.” The number of turns keeps changing, but the rest of the message stays the same.

Have the Right Number of Values

To make a silly sentence, you need to mix up a heap of words into a message template. Substitute more than just one word into a template. To do that, follow these steps:

  1. Include additional specifiers in the template.
  2. List the values to be converted as if they were a list, but put parentheses around them instead of the square brackets used for a list.
  3. Make sure the number of specifiers is equal to the number of values to be converted.

A quick example:

>>> "%s %s"%(1,2)

'1 2'

You get an error if the number of specifiers doesn’t match the number of values to be formatted. Try these:

"%s %s"%(1) (two specifiers, one value)

"%s %s"%(1,2,3) (two specifiers, three values)

Pay attention to the errors; sooner or later you’ll need them for debugging. You can pre-save your values before you pass them to your format string:

>>> values = (1,2)

>>> "%s %s"%values

'1 2'

>>> # Snuck in a tuple:

>>> type(values)

<type 'tuple'>

The formatting operator takes only one argument. When you place parentheses around a number of items separated by commas, you actually get a new object called a tuple. It is this single object that is passed to the formatting operator.

Use the Tuple Data Type

You’ll have a couple of buckets of words for the silly sentences. Choose one word from each bucket and put them together. The formatting operator only takes one argument, so pack all the words into an object so you can pass it, as a single argument, to the formatting operator. For that you need a tuple.

Tuples are the most misunderstood Python data type. They’re a bit like lists. Some people think tuples are worse than lists, but they’re just different. You can get the values of the elements of a tuple, but you can’t change them. Tuples are immutable, which is a fancy way of saying you can’t change them.

Tuples are good for

  • When you have values that you want to put in a specific order. That’s exactly what you want when you’re using a format string.
  • When you have a set of values that you don’t want changed (either on purpose or by accident).

tip Tuple elements have a meaningful order. Lists are for things where order doesn’t matter.

You can iterate (go) through tuples like you would a list and can read individual elements like a list:

>>> my_tuple = ('e','3')

>>> for e in my_tuple:

        print(e)

 

 

e

3

>>> my_tuple[0]

'e'

>>> my_tuple[1]

'3'

>>> my_tuple(0) # use [] not ()!

 

Traceback (most recent call last):

 File "<pyshell#42>", line 1, in <module>

    my_tuple(0) # [] not ()!

TypeError: 'tuple' object is not callable

Here, my_tuple[0] retrieves the value of the first element (elements are numbered from 0) in the tuple. It has the same square bracket notation that lists have. The number of the elements starts from 0, just like the substitutions were in the 133t sp34k3r project.

Confirm that you can’t change the element by trying to assign a value to element 0: my_tuple[0] = 17. Be familiar with the error (it will tell you that tuples don’t support item assignment) so you’ll recognize it when you see it later.

You can have a tuple with only one element. Why? Because the code you want to use might expect a tuple. How would you make a tuple with only one element? The answer is to proceed as normal, putting parentheses around your one element, but to add a comma after it.

>>> my_one_element_tuple = (1,)

>>> my_one_element_tuple

(1,)

The comma tells Python that it’s a tuple; technically it’s the comma, not the parentheses, that’s doing the work. You usually need to use parentheses because the syntax is hard to figure out.

Tuples let you return more than one value from a function, which is handy when you want to return more than one value from a function. But the code calling the function can treat the values as a single tuple or as individual elements. This is called unpacking the tuple.

You have to give the tuple exactly the right number of elements if you want the values unpacked. For example, here the test_function returns a tuple with three values (1,2,3). The code can either receive it as a single object a= test_function() or as three separate objects in a,b,c = test_function(), but not as any other number.

You can use this approach when you want to return more than one value from a function:

>>> def test_function():

        return (1,2,3) # returns a tuple with three elements

 

>>> a = test_function()

>>> a

(1, 2, 3)

>>> a,b,c = test_function()

>>> a

1

>>> b

2

>>> c

3

>>> a,b = test_function()

 

Traceback (most recent call last):

  File "<pyshell#59>", line 1, in <module>

    a,b = test_function()

ValueError: too many values to unpack

You can also unpack a tuple directly:

>>> a,b,c = (1,2,3) # unpack the tuple into a, b, c

>>> print("a: %s, b: %s, c: %s"%(a,b,c))

a: 1, b: 2, c: 3

>>> a,b = (1,2,3) # three values but only two variables.

 

Traceback (most recent call last):

  File "<pyshell#62>", line 1, in <module>

    a,b = (1,2,3)

ValueError: too many values to unpack

Get Started on Your Silly Sentences

To make silly sentences, you need a template where you can plug in some words. Think of this like:

<Person or animal> <verbed> the <adjective> <noun>.

(Yeah, yeah. I know verbed isn’t a word.) A formatting template for this would look like what you see here. Each %s is a conversion specifier and marks a place where a value will be inserted into the string:

template = "%s %s the %s %s."

Time to get started on your silly sentences:

  1. Create a new file and name it silly_sentencer.py.
  2. Add a comment at the top of the file that explains what the program will do.

    """silly_sentencer.py

    This program prints silly sentences by mapping random words

    into a formatting template

    Brendan Scott

    Jan 2015

    """

  3. Create a template based on <Person or animal> <verbed> the <adjective> <noun>:

    template = "%s %s the %s %s."

  4. Store the following sample in a constant called BASE_SENTENCE.

    You’ll look at this sentence when you’re testing your code.

    BASE_SENTENCE = "My Python teacher wrote the Python book."

  5. Type the following into your code:

    persons = ["My Python teacher"]

    verbs = ["wrote"]

    adjectives = ["Python"]

    nouns = ["book"]

    tip When you’re first working on a project, start simple. Make it more complex later. Don’t try to conquer the universe in your first go. That way, miMMisMistakes are easier to find and fix.

    You should have something that looks like this:

    """silly_sentencer.py

    This program prints silly sentences by mapping random words

    into a formatting template

    Brendan Scott

    Jan 2015

    """

     

    BASE_SENTENCE = "My Python teacher wrote the Python book."

    template = "%s %s the %s %s."

     

    persons = ["My Python teacher"]

    verbs = ["wrote"]

    adjectives = ["Python"]

    nouns = ["book"]

Now test to make sure that applying the values from the lists to the template gives you the base sentence.

  1. Create a Main section.
  2. Add the following code and run the file.

    This code creates a tuple from the first element of each list, then passes that tuple into the formatting string. The last print statement compares whether the formatted string is the same as what you started with:

    # Main Section

    if __name__ == "__main__":

        person = persons[0]

        verb = verbs[0]

        adjective = adjectives[0]

        noun = nouns[0]

     

        format_values = (person, verb, adjective, noun)

     

        print(BASE_SENTENCE)

        print(template%format_values)

        print(BASE_SENTENCE == template%format_values)

You should get this:

>>> ================================ RESTART ================================

>>>

My Python teacher wrote the Python book.

My Python teacher wrote the Python book.

True

Fill the Template

To fill in the template, choose an element from each list at random. Because there’s only one element in each list at the moment, it’s not all that random. However, you’re testing with one element and then adding other elements later. When you have that, you can use the code you already have to populate the template with the words you’ve chosen.

Choosing at random from a list is relatively easy. Use the choice function from the random module. In this example I use a list comprehension to make a list with the numbers from 0 through 9, then I use random.choice to choose one of them at random:

>>> import random

>>> sample_list = [x for x in range(10)]

>>> random.choice(sample_list)

1

Now bring it all together in your code:

  1. Remove, or comment out, the print statements and other code included for testing.
  2. Replace each assignment like person = persons[0] with something like person = random.choice(persons).
  3. Make a tuple with the format values.
  4. Print out the base sentence for comparison and the template formatted with the format values.

    Here’s the code:

    """silly_sentencer.py

    This program prints silly sentences by mapping random words

    into a formatting template

    Brendan Scott

    Jan 2015

    """

    # Imports Section

    import random

     

    # Constants Section

    BASE_SENTENCE= "My Python teacher wrote the Python book."

    template = "%s %s the %s %s."

     

    persons = ["My Python teacher"]

    verbs = ["wrote"]

    adjectives = ["Python"]

    nouns = ["book"]

     

     

    # Main Section

    if __name__ == "__main__":

        person = random.choice(persons)

        verb = random.choice(verbs)

        adjective = random.choice(adjectives)

        noun = random.choice(nouns)

     

        format_values = (person, verb, adjective, noun)

     

        print(BASE_SENTENCE)

        print(template%format_values)

  5. Run it!

    You’re testing that the function works properly.

    >>> ================================ RESTART ================================

    >>>

    My Python teacher wrote the Python book.

    My Python teacher wrote the Python book.

This code looks like it’s working right. The first line is the original string you started with. The second is the string you created using the formatting template.

Add More Words

Now you can get creative. For each list think of other words which you could put in there. You haven’t tested your code with a list longer than one yet, so just add words to a single list, not all of them at once.

The other words that you’re choosing:

  • Must be the same type as the original word. For example, for persons you might add The Hungarian and for adjectives you might add slippery, but you wouldn’t do the reverse. Otherwise, the sentence wouldn’t make any sense: “slippery was The Hungarian.”
  • Should be single words. They can be multiples. For example, Mrs Pepperpot or The Hungarian.
  • Shouldn’t be pronouns: he, she, it, we, us, they. You’d need to match the pronoun to the gender.

Here are some extra words to get you started:

persons = ["My Python teacher", "Dinsdale Piranha", "Tim", "Mrs Pepperpot", "My dad", "The Hungarian"]

verbs = ["wrote", "sneezed", "looked at", "drove", "made", "stole"]

adjectives = ["Python", "slippery", "funniest", "big", "smelly", "poky", "silly"]

nouns = ["book", "eels", "hovercraft", "nose", "shoes", "joke", "walk"]

You can split a long list

over multiple lines. (Like that.)

You can add a new line after any comma.

When you’ve got all the elements you want, finish with a closing square bracket (and no comma). Run the code a few times to see if it works. (I removed the restart lines from this printout.)

Mrs Pepperpot looked at the big eels.

My dad sneezed the funniest shoes.

Dinsdale Piranha wrote the Python book.

Dinsdale Piranha wrote the silly nose.

Tim made the Python shoes.

My dad made the Python walk.

My Python teacher drove the slippery joke.

Tim wrote the Python shoes.

Everything seems to be working. This function is a little hard to test because the output is random (unlike addition, where you know what the answer should be).

When you’re satisfied, you can finish filling out your word lists. If you like, you can also put the whole section into a for loop to print multiple sentences each time you run the program.

The Complete Code

If you add those changes to the previous code, you get your final code. It looks like this:

"""silly_sentencer.py

This program prints silly sentences by mapping random words

into a formatting template

Brendan Scott

Jan 2015

"""

 

# Imports Section

import random

 

# Constants Section

BASE_SENTENCE = "My Python teacher wrote the Python book."

template = "%s %s the %s %s."

persons = ["My Python teacher", "Dinsdale Piranha", "Tim", "Mrs Pepperpot", "My dad", "The Hungarian"]

verbs = ["wrote", "sneezed", "looked at", "drove", "made", "stole"]

adjectives = ["Python", "slippery", "funniest", "big", "smelly", "poky", "silly"]

nouns = ["book", "eels", "hovercraft", "nose", "shoes", "joke", "walk"]

 

 

# Main Section

if __name__ == "__main__":

    person = random.choice(persons)

    verb = random.choice(verbs)

    adjective = random.choice(adjectives)

    noun = random.choice(nouns)

 

    format_values = (person, verb, adjective, noun)

 

##    print(BASE_SENTENCE)

    print(template%format_values)

Summary

In this project you used Python's formatting operator % to produce silly sentences. Along the way you saw:

  • Format strings, a formatting operator, a formatting value, and conversion specifiers.
  • The string conversion specifier: %s.
  • A new data type — the immutable (can't be changed) tuple.
  • That tuples store elements with a meaningful order, can return multiple values from a function, and can be unpacked: a, b = (1,2).
  • The random.choice function and how to use it to get an element at random from a list.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.119.66