A document from MCS 260 Fall 2021, instructor David Dumas. You can also get the notebook file.

MCS 260 Fall 2021 Worksheet 9

  • Course instructor: David Dumas

Topics

This worksheet focuses on dispatch tables, operators on iterables (e.g. any(), all()), and modules.

Problem 1 treated differently

Following the new policy, Problem 1 is different in that:

  • Tuesday lab students: Problem 1 will be presented and solved as a group, in a discussion led by your TA.
  • Thursday lab students: Please attempt problem 1 before coming to lab. Bring a solution, or bring questions. The problem will be discussed as a group.

Resources

The main course materials to refer to for this worksheet are:

(Lecture videos are not linked on worksheets, but are also useful to review while working on worksheets. Video links can be found in the course course Blackboard site.)

1. Refactoring terminal2.py

Recall that we developed a simple terminal application called terminal2.py. Download this program and save it under a new name, terminal3.py.

Then, modify the program as follows:

Move commands to a module

Create a module called termcommands (in a file called termcommands.py) and move all the terminal commands out of terminal3.py and into this file. That means all the functions that begin with do_ should be moved. Also move the dispatch table into the module.

Have terminal3.py import and use this module, so that when you're done it works in the same way as terminal2.py. Test running it, and make sure the commands work.

New command

Add a new command called haspy? (think of that as "has python?") that simply prints "yes" or "no" depending on whether the current directory contains any files whose names end in .py. It should be implemented by a function do_haspy that is in the module termcommands. You'll need to add a new entry to the dispatch table, of course.

If you use list comprehensions and any() in a clever way, you can make do_haspy a one-line function. After you get it working by any method, see if you can achieve a one-line version.

2. Comment line zapper

Write a program called commentzapper.py that takes one command line argument, which is expected to be the name of a Python file. It should read that file and print all the code, except it should skip any lines that consist entirely of comments (i.e. no code at all).

For example, suppose that example.py contains the code below:

In [ ]:
# Save this as `example.py` if you want to test the counter program
"Sample of counting"
# MCS 260

def this_line_counts():  # I am a comment on a line that contains code
    "I am a docstring!"
    # TODO: Fix this!
    print("Hello.")

this_line_counts()

Then running

python commentzapper.py example.py

should print the following:

"Sample of counting"

def this_line_counts():  # I am a comment on a line that contains code
    "I am a docstring!"
    print("Hello.")

this_line_counts()

Hint: This is an ideal problem in which to try out Python's continue statement that we learned about last week. If you solve it another way, try to figure out how you might use continue.

3. Iterable puzzles

Here's a JSON file that contains a list of 100 lists of words.

The word lists have various lengths, and were selected randomly from a large dictionary.

To complete this problem you'll need that file and some code to load it into a variable in Python. Here's an example of code that can do so:

In [ ]:
import json

# We assume "iterpuzzles.json" is in the CWD
fobj=open("iterpuzzles.json","r",encoding="UTF-8")
L=json.load(fobj)
fobj.close()

The rest of this problem consists of puzzles that assume you have the data from that file in a variable called L.

Each puzzle asks you to write an expression in Python, ideally one line, that answers the question.

We start with a few examples (with solutions).

Ex1. What's the first element of L?

In [46]:
L[0]
Out[46]:
['antlia',
 'stauromedusae',
 'pandestruction',
 'tabellariaceae',
 'noninferable',
 'papillitis',
 'bairnly',
 'battutos',
 'megaphonically',
 'unpurpled',
 'irredentists',
 'headships',
 'hemitype',
 'phasmatoid',
 'amimide',
 'squamae',
 'acronychous',
 'ganisters',
 'existimation',
 'appallingness',
 'unworshipping',
 'pachyhymenia',
 'rosicrucian',
 'snowbells']

Ex2. Do any of the lists in L contain exactly 17 words?

In [38]:
any( [ len(x)==17 for x in L ] )
Out[38]:
True

(This means the answer is "yes". An example is L[92], as you can check.)

Ex3. Does every element of L have a first element with at least 5 letters?

In [32]:
all( [ len(x[0]) >= 5 for x in L ] )
Out[32]:
False

(This means the answer is "no". You can check that L[53] begins with "lamp".)

Ex4. Are there any lists in L consisting entirely of words of even length?

In [24]:
any( [ all( [len(w)%2==0 for w in x] ) for x in L ] )
Out[24]:
True

(This means the answer is "yes". An example is L[7], which contains words of lengths [8, 6, 6, 14, 8, 8].)

Now the actual problems.

A. Does every list contain a word starting with e?

B. Does the word "antipathy" appear in any of the lists?

C. How many of the lists contain an odd number of words?

D. For which i is L[i] a list in which the second word begins with the letter a?

4. Multiple input of specified types

Write a function multi_input(L) that accepts a list like ["float", "string", "integer", "letter"] and reads corresponding input from the keyboard, returning a list of results. Thus, if given the list above as input, the function might return [ 8.5, "Chicago", 31, "g" ].

Specifically: Each item in the list given as an argument will be a string, and is meant to specify the expected type of one line of input. The possible values are:

  • "float" - indicates a float value is to be read
  • "integer" - indicates an integer is to be read
  • "string" - indicates a string is to be read
  • "letter" - indicates a single letter is to be read

If the actual input does not match the expected type, the function should print a message and try again.

Here is a sample interaction with multi_input( ["float", "string", "integer", "letter"] ):

float: asdf
That didn't work; expected entry of a float.
float: 8.5
string: Chicago
integer: Denver
That didn't work; expected entry of a integer.
integer: 31
letter: jkl
That didn't work; expected entry of a letter.
letter: g

The return value in this case would be [ 8.5, "Chicago", 31, "g" ].

Please use a dispatch table with keys "float", "integer", "string", "letter".

Revision history

  • 2021-10-18 Initial release