It’s been a long time since I’ve written a blog post. As I have written previously, I intentionally scaled back on my blogging. I didn’t want to scale back to the point that I have not written a post since July. But my life has been busy lately, a topic that may be the subject of a future post (for those who care about what goes on in my life).

Aside from my video courses, I have not done any serious Python programming. However, I did finish a day project that I’ve wanted to do for a while: write a Python Mad Lib program.

For those of you who don’t know, Mad Libs are a word game for generating humorous stories. One player (working effectively as a game master) picks a story template, which is a story with certain parts–nouns, verbs, adjectives, etc.–omitted. The player asks for these sentence parts from other participants without revealing the context and fills the words in. At the end the resulting story, filled with nonsense, is read aloud.

Writing a Python Mad Lib program makes good practice for string manipulation, particularly for substring replacement and code organization via classes. In order to write such a program you need:

A string that contains the story template Some objects that manages “blank spaces”, including describing the appropriate part of speech for the “blank” and the users’ response A method for prompting for and managing user input A method for generating the completed Mad Lib A method for displaying the resulting story.

This is all best managed via a class. As for string manipulation, by far the easiest solution is to rely on the format() method supplied with strings. It’s hard to beat the notation "I went to the {noun} today.".format(noun="park") or "I went to the {noun1} today with my {noun2}.".format(**words) where words = {"noun1": "park", "noun2": "dog"} .

Additionally, this project demonstrates class inheritence as well. We can write a MadLib object that abstractly manages these tasks, providing a framework and methods, without actually containing a worthwhile Mad Lib. This allows for easy generalization; future Mad Lib objects subclass the MadLib object and all future authors need to do is provide the story string and the description of the “blanks”.

Below I’ve provided code for the base class and a few examples. The code can be stuck in files and made executable on Linux systems.

#!/usr/bin/python3 __doc__ = """ Provides the MadLib object, a template for creating madlibs; see the documentation of MadLib for instructions on how to properly subclass it for creating new madlib generators. An example madlib generator object, called MurderMadLib, is provided. """ __author__ = "Curtis Miller" __copyright__ = "Copyright (c) 2017, Curtis Grant Miller" __credits__ = ["Curtis Miller"] __license__ = "GPL" __version__ = "0.1.0" __maintainer__ = "Curtis Miller" __email__ = "cgmil@msn.com" __status__ = "Experimental" class MadLib(object): """An object for managing madlibs. A new madlib subclassed from this object should change only the __init__() method, and assign a new _text (string for formatting) & _descriptors (dict) _inputs should always be an empty dict (it's okay if it's not, but its contents will be reset by get_inputs(), so any content put there will do nothing). _text should be a string that the format() method can work with, being passed keys of a dict; an example of a valid _text is "One day, a {occupation1} {verb1} to a {place1} to buy {object1}s." _descriptors has keys corresponding to EVERY field in _text (errors will be thrown if this is not the case) and values that instruct users, in the prompt, what is desired. (So, for example, a key/value pair would be: "occupation1": "an occupation for a person (e.g. firefighter)" and so on.) """ def __init__(self): """Initialization; get initial objects This is the only method changed when creating new madlibs. Declares _text and _descriptors """ self._text = "" self._descriptors = dict() def get_inputs(self): """Prompt the user (via command line) for input, and store in _inputs """ self._inputs = dict() # Reset inputs for k, v in self._descriptors.items(): # Prompt for input self._inputs[k] = str(input("I need " + v + ": ")) def print_result(self): """Print the resulting mad-lib""" try: print(self._text.format(**self._inputs)) except Exception as e: raise AssertionError("You should run get_inputs() first!") class MurderMadLib(MadLib): def __init__(self): """initialization; story related to a murder""" # Original source: # http://www.sltrib.com/home/5476673-155/utah-man-charged-with-murder-in # (it's actually depressing, by the way) self._text = " ".join(["A MURDER CASE", "

-------------", "



A {age3}-year-old {town1} man has been", "charged with", # Sorry for bad formatting 😦 "{crime1} and {crime2} in the death last year of", "{living1}.



{boy1} made an initial appearance", "on Monday in {place1}, where he is charged with", "first-degree felony {crime1} and three counts", "of second-degree felony {crime2} in connection", "with {living1}.



{living1} was pronounced", "dead on Nov. 1 after {boy1}, then {age1}, and", "{living1}'s' {age2}-year-old {living2} brought", "the unresponsive {living1} to {place2}.



An", "autopsy later determined {living1} died from", "\"{injury1} to the {bodypart1}, with associated", "trauma to the {bodypart2} all consistent with", "non-accidental {verb1} ... ,\" according to", "charging documents.



The autopsy also", "revealed evidence of possible attempted {verb2}", "or {verb13}, a fresh {bodypart3} {injury2},", "and an older, healing {bodypart4} injury,", "charges state.



{boy1} told police", "investigators that he took over the care of", "{living1} at about 11:30 p.m. that night, and", "that he was keeping {living1} up late so he", "would {verb3} through the night.



{boy1} told", "police that he was watching {object1} with", "{living1} when, at about 3:10 a.m., he found", "{living1} was \"{adjective1}\" and would not", "{verb4}, charges state.



He woke {living1}'s", "{living2} and they {verb5}, then took {living1}", "to {place3} in their {object2}, charges", "state.



{boy1}'s sister later told police", "that he and {living1}'s {living2} \"were having", "a hard time {verb6},\" and that she was looking", "after {living1} about once a week because they", "were \"frustrated with {living1},\" charges", "state.



A scheduling hearing in the case is", "set for July 17.



{boy1} was being held at", "the {town1} jail in lieu of ${dollar1} bail,", "cash-only.



Meanwhile, {boy1} has two other", "pending court cases.



He is charged with", "second-degree {crime3} for {verb7} a {object3}", "found on his {object4} that shows him {verb8}", "with the {living2} of {living1}.



He also is", "charged with two counts of {crime4} for", "allegedly {verb9} at a {noun1} and a {noun2}", "last August in {town2}. The alleged victims", "were trying to {verb10} when they asked {boy1}", "to {verb11}, charges state. {boy1} responded by", "{verb12} and {verb14}, charges state."]) self._descriptors ={"town1": "a city or town", "town2": "a city or town", "crime1": "a crime", "crime2": "a crime", "crime3": "a crime", "crime4": "a crime", "boy1": "a boy's name", "place1": "a place for people (e.g. gas station)", "place2": "a place for people (e.g. gas station)", "place3": "a place for people (e.g. gas station)", "living1": ' '.join(["a living thing (specific", "tense, like \"the bird\" or", "\"Sam Smith\""]), "living2": "a living thing (no articles)", "injury1": "a word describing an injury (one word)", "injury2": "a word describing an injury (one word)", "bodypart1": "a bodypart", "bodypart2": "a bodypart", "bodypart3": "a bodypart", "bodypart4": "a bodypart", "object1": "an object", "object2": "an object", "object3": "an object", "object4": "an object", "verb1": "a verb or action (e.g. \"running\")", "verb2": "a verb or action (e.g. \"running\")", "verb13": "a verb or action (e.g. \"running\")", "verb3": "a verb (e.g. \"run\")", "verb4": "a verb (e.g. \"run\")", "verb5": "a verb or action (e.g. \"flipped\")", "verb6": "a verb or action (e.g. \"running\")", "verb7": "a verb or action (e.g. \"running\")", "verb8": "a verb or action (e.g. \"running\")", "verb9": "a verb or action (e.g. \"running\")", "verb10": "a verb (e.g. \"run\")", "verb11": "a verb or action (e.g. \"run\")", "verb12": "a verb or action (e.g. \"running\")", "verb14": "a verb or action (e.g. \"running\")", "noun1": "a noun", "noun2": "a noun", "age1": "an age (in years)", "age2": "an age (in years)", "age3": "an age (in years)", "dollar1": "an amount of money", "adjective1": "an adjective"} if __name__ == '__main__': # Run demo madlib demo = MurderMadLib() demo.get_inputs() print("



") demo.print_result()

#!/usr/bin/python3 __doc__ = """ Extra mad libs, for fun. """ __author__ = "Curtis Miller" __copyright__ = "Copyright (c) 2017, Curtis Grant Miller" __credits__ = ["Curtis Miller"] __license__ = "GPL" __version__ = "0.1.0" __maintainer__ = "Curtis Miller" __email__ = "cgmil@msn.com" __status__ = "Experimental" from MadLib import MadLib class EmperorMagicianML(MadLib): """ A madlib about an emperor and a magician """ def __init__(self): self._descriptors = {"boy1": "a boy's name", "emotion1": "an emotion", "emotion2": "an emotion", "occupation1": "a job or occupation", "verb1": "a verb (past tense, like \"jumped\")", "superlative1": "a superlative (e.g. \"best\")", "superlative2": "a superlative (e.g. \"best\")", "occupation2": "a job or occupation", "adjective1": "an adjective", "name1": "a name", "adjective2": "an adjective", "verb2": "a verb (present simple third person" +\ ", like \"hates\" or \"jumps\")", "living1": "a living thing", "place1": "a place (cannot be a proper noun)", "adjective3": "an adjective", "adjective4": "an adjective", "noun1": "a dwelling", "verb3": "a verb (past tense)", "noun2": "a noun (cannot be a proper noun)", "adverb1": "an adverb", "noun3": "a dwelling", "object1": "an object", "verb4": "a verb", "verb5": "a verb", "verb6": "a verb", "emotion3": "an emotion (as a noun, e.g." + \ " \"anger\" or \"happiness\")", "verb7": "a verb", "adjective5": "an adjective", "place2": "a place (specific tense, either a " + \ "proper noun or beginning with \"the\")", "noun4": "a noun (cannot be a proper noun)", "bodypart1": "a bodypart", "bodypart2": "a bodypart", "adverb2": "an adverb", "bodypart3": "a bodypart", "verb8": "a verb (past tense)", "verb9": "a verb (active tense, like \"jumping\")", "verb10": "a verb (past tense)", "verb11": "a verb (past tense)", "adjective6": "an adjective"} self._text = ' '.join(["The Emperor and the {occupation2}", "

---------------------------------

" "

Once upon a time there was a young emperor", "ruling over a distant land, named {boy1}. One", "day {boy1} was {emotion1}. \"I'm {emotion2},\"", "{boy1} told his {occupation1}. \"I wish to be", "{verb1}! Bring me the {superlative1}", "{occupation2} in all the land!\"



\"Well,", "that would be the {adjective1} {occupation2},", "{name1} the {adjective2},\" {boy1}'s", "{occupation1} replied. \"Unfortunately, I fear", "that {name1} {verb2} your rule.\"



\"I do", "not care,\" {boy1} replied. \"See that {name1}", "comes here immediately!\"



So {boy1}'s", "{living1} travelled through the land to find", "{name1} the {adjective2}. They found {name1}", "deep in the {place1} in a {adjective3}", "{adjective4} {noun1}. They {verb3} on", "{name1}'s {noun2}, saying, \"The emperor", "{boy1} demands your presence!\"



\"Then", "I shall go,\" {name1} said {adverb1}.



The", "journey took days, but {name1} eventually", "arrived at {boy1}'s {noun3}, and stood before", "{boy1}'s {object1}, and began to {verb4}.", "



\"I shall now {verb5} my {superlative2}", "trick,\" {name1} said, which made {boy1}", "{verb6} in his {object1} with {emotion3}.", "\"I shall {verb7} a {adjective5} {noun4} into", "{place2}, where it shall never be seen again!", "And I shall do so with just my {bodypart1}.\"", "{name1} waved his/her {bodypart2} {adverb2},", "then poked out his/her {bodypart1}, and threw", "it above his/her {bodypart3}. Suddenly {boy1}", "{verb8} from his {object1}, {verb9}, and", "{verb10} many miles out of sight. Then {name1}", "{verb11} upon {boy1}'s {object1}, and", "proclaimed himself Emperor/herself Empress.", "



The reign of Emperor/Empress {name1} was", "{adjective6}, while {boy1} was never seen", "again."]) if __name__ == '__main__': madlib_choices = [EmperorMagicianML] choice = str(input("Pick a number between 1 and " + \ str(len(madlib_choices)) + " (an integer): ")) choice = int(choice) - 1 ml = madlib_choices[choice]() ml.get_inputs() print('



') ml.print_result()

I would love to see others write their own Mad Libs using my code and share it here. There are a few guides for doing this, but here’s what I would suggest:

Get a story. You could start by writing your own (I did that for one of the above), without caring about how good it actually is. Another idea would be to get some document, such as a story from a newspaper (the other Mad Lib came from this) or a letter or guide or speech. Start deleting words. A couple words from a sentence would be good. Create the code.

I conclude with a story I generated. Please, share your code and stories in the comments. I would love to see what you get!

The Emperor and the professor

Once upon a time there was a young emperor ruling over a distant land, named John. One day John was afraid. “I’m loved,” John told his janitor. “I wish to be walked! Bring me the loveliest professor in all the land!” “Well, that would be the slimy professor, Amy the young,” John’s janitor replied. “Unfortunately, I fear that Amy paints your rule.” “I do not care,” John replied. “See that Amy comes here immediately!” So John’s banker travelled through the land to find Amy the young. They found Amy deep in the shop in a moist red dorm. They lay on Amy’s board, saying, “The emperor John demands your presence!” “Then I shall go,” Amy said greedily. The journey took days, but Amy eventually arrived at John’s houseboat, and stood before John’s ticket, and began to float. “I shall now shuffle my squishiest trick,” Amy said, which made John climb in his ticket with boredom. “I shall jump a tired bus into University of Utah, where it shall never be seen again! And I shall do so with just my foot.” Amy waved her nose slowly, then poked out her foot, and threw it above her finger. Suddenly John drove from his ticket, shopping, and grabbed many miles out of sight. Then Amy sucked upon John’s ticket, and proclaimed herself Empress. The reign of Empress Amy was hard, while John was never seen again.

(I know it’s not very good, but I don’t care.)

I have created a video course entitled Unpacking NumPy and Pandas, the first volume in a four-volume set of video courses entitled, Taming Data with Python; Excelling as a Data Analyst. This course covers the basics of setting up a Python environment for data analysis with Anaconda, using Jupyter notebooks, and using NumPy and pandas. If you are starting out using Python for data analysis or know someone who is, please consider buying my course or at least spreading the word about it. You can buy the course directly or purchase a subscription to Mapt and watch it there (when it becomes available).

If you like my blog and would like to support it, spread the word (if not get a copy yourself)! Also, stay tuned for future courses I publish with Packt at the Video Courses section of my site.