A document from MCS 275 Spring 2022, instructor Emily Dumas. You can also get the notebook file.

MCS 275 Spring 2022 Homework 4 Solutions

  • Course Instructor: Emily Dumas
  • Solutions prepared by: Emily Dumas, Johnny Joyce

Instructions:

  • Complete the problems below, which ask you to write Python scripts.
  • Upload your python code directly to gradescope, i.e. upload the .py files containing your work. (If you upload a screenshot or other file format, you won't get credit.)

Deadline

This homework assignment must be submitted in Gradescope by Noon central time on Tuesday 8 February 2022.

Collaboration

Collaboration is prohibited, and you may only access resources (books, online, etc.) listed below.

Resources you may consult

The course materials you may refer to for this homework are:

Point distribution

This homework assignment has two problems, numbered 2 and 3. The grading breakdown is:

Points Item
2 Autograder
4 Problem 2
4 Problem 3
10 Total

The part marked "autograder" reflects points assigned to your submission based on some simple automated checks for Python syntax, etc.. The result of these checks is shown immediately after you submit.

What to do if you're stuck

Ask your instructor or TA a question by email, in office hours, or on discord.

Problem 1 doesn't exist

In Gradescope, the score assigned to your homework submission by the autograder (checking for syntax and docstrings) will be recorded as "Problem 1". Therefore, the numbering of the actual problems begins with 2.

Problem 2: 2-argument to n-argument

Here is a function that takes two strings s and t and returns a string that contains all the letters that appear in both s and t. The order in which the characters appear in the return value isn't important, but the function is written in such a way that it will return them in the order they appear in s.

In [3]:
def common_letters2(s,t):
    "Return a string with distinct characters, consisting of the characters that appear in both s and t"
    common = []
    for c in s:
        if c in common:
            continue
        if c in t:
            common.append(c)
    return "".join(common)

# This isn't the only way, nor the most efficient or natural way to accomplish this in Python
# We'll return to this function later and learn another way to do it!

Here is an example of its use:

In [11]:
common_letters2("evolving situation","inferior sandwich")
Out[11]:
'eoin sa'
In [17]:
common_letters2("aabbccddeeff","global foxtrot aaaaa")
Out[17]:
'abf'

Use this function to write another function common_letters that accepts any number of strings as arguments, and which returns a string that contains the letters that appear in every string that was given as an argument. Put your function in a file hwk4prob2.py.

Note: Your solution must make essential use of common_letters2.

Sample usage of common_letters:

In [12]:
common_letters("abacus","diagonal","ocean madness")
Out[12]:
'a'
In [10]:
common_letters("Python expert","noisome ruminant","tenured onion")
Out[10]:
'ton er'
In [11]:
common_letters("a-b-c-d","b^c^d^e","c_d_e_f")
Out[11]:
'cd'

Solution

In [9]:
def common_letters(*args):
    '''Given any number of strings as args, returns single
    string containing letters appearing in every string'''
    
    # Handle special cases where there are only 0 or 1 argument(s)
    if len(args)==0:
        return ""
    if len(args)==1:
        return args[0]
    
    common = args[0] # Start with every letter from the first arg
    for arg in args[1:]: # Iterate over each subsequent arg
        common = common_letters2(common, arg) # Update common to only have letters in the current arg
    return common

Problem 3: Do nothing if file is missing

If a function attempts to open a file that doesn't exist, a FileNotFoundError exception will be raised.

Write a decorator ignore_missing that, if attached to such a function, will just ignore the FileNotFoundError. Thus, with the decorator applied, the function will return as soon as it fails to open a file, with no exception. Put your decorator in a file hwk4prob3.py.

For example, the following code raises an exception if "asdf.txt" does not exist:

In [29]:
def openit():
    "Open 'asdf.txt' for reading"
    with open("asdf.txt","r") as fobj:
        return "Success!"
    
openit()  # Exception because "asdf.txt" does not exist
print("Hey look, this line never runs")
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-29-f06792d5c7b9> in <module>
      3         return "Success!"
      4 
----> 5 openit()  # Exception because "asdf.txt" does not exist
      6 print("Hey look, this line never runs")

<ipython-input-29-f06792d5c7b9> in openit()
      1 def openit():
----> 2     with open("asdf.txt","r") as fobj:
      3         return "Success!"
      4 
      5 openit()  # Exception because "asdf.txt" does not exist

FileNotFoundError: [Errno 2] No such file or directory: 'asdf.txt'

But if you apply the decorator, it should no longer do so:

In [35]:
@ignore_missing
def openit():
    "Open 'asdf.txt' for reading"
    with open("asdf.txt","r") as fobj:
        return "Success!"
    
openit()  # Will do nothing because the `FileNotFound` is caught
print("Hey look, it ignored the missing file.")
Hey look, it ignored the missing file.

Solution

In [14]:
def ignore_missing(f):
    '''Decorator for ignoring any FileNotFoundErrors'''
    
    def inner(*args, **kwargs):
        '''Inner function to be returned by ignore_missing'''
        try:
            return f(*args, **kwargs) # Run the decorated function as normal
        except FileNotFoundError:
            pass # <- Do absolutely nothing!
            
    return inner # Note the lack of parentheses after inner. Function is being returned, but not being run.

And to test the decorator...

In [15]:
@ignore_missing
def openit():
    "Open 'asdf.txt' for reading"
    with open("asdf.txt","r") as fobj:
        return "Success!"
    
openit()  # Will do nothing because the `FileNotFound` is caught
print("Hey look, it ignored the missing file.")
Hey look, it ignored the missing file.