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

Quiz 4 Solutions

MCS 275 Spring 2021 - Emily Dumas

Solutions by Jennifer Vaccaro

Instructions:

Deadline

This quiz must be submitted in Gradescope by 12:00pm CST on Tuesday, Februrary 9, 2021.

Topic

This quiz focuses on the material from Worksheet 4.

Resources you are allowed to consult

Quizzes are INDIVIDUAL, closed book, and only allow access to specified resources. For this quiz you can access:

Cite your sources

If you adapt code from any course documents (e.g. worksheet solutions), you need to indicate that in the required declaration comment at the top of the source file.

Point distribution

This quiz has 2 problems (numbered 2 and 3), each worth 4 points. Therefore, the final grading breakdown is:

Points Item
3 autograder
4 problem 2
4 problem 3
11 total

(No problem number 1, as usual)

The points assigned by the autograder based on syntax and docstring checking will be listed as problem 1 in Gradescope.

Problem 2: Argument with maximum digit sum

For the purposes of this problem, the digit sum of an integer is the sum of all of its decimal digits, e.g.

  • The digit sum of 1205 is 1+2+5 = 8
  • The digit sum of 99 is 9+9 = 18

Write a function called max_digit_sum that takes any number of nonnegative integer arguments (but requires at least one argument), and determines which of its arguments has the largest digit sum, and returns that argument. If several arguments are tied for largest digit sum, the function should return the one appearing earliest in the argument list.

Put this function in a file called quiz4prob2.py and submit it.

Examples:

In [1]:
# MCS 275 Quiz 4 Problem 2
# Jennifer Vaccaro
# I wrote this code in accordance with the rules defined in the syllabus.

def digit_sum(n):
    """Given an integer n, returns the sum of the digits."""
    total = 0
    for digit in str(n): # iterate over the digits
        total += int(digit) # add each digit to total
    return total

def max_digit_sum(*args):
    """Takes in at least one numeric argument, 
    then returns the arg with the maximal digit_sum"""
    max_sum = -1 # Every number will have a non-negative digit_sum
    for arg in args:
        arg_sum = digit_sum(arg)
        if arg_sum > max_sum: # Replace max_arg only if the arg's digit_sum is greater
            max_arg = arg
            max_sum = arg_sum
    return max_arg # raises an exception if no argument given.
In [2]:
max_digit_sum(1205,99)  # 99 has largest digit sum 18
Out[2]:
99
In [3]:
max_digit_sum(156213)   # just returns the only argument given
Out[3]:
156213
In [4]:
max_digit_sum(11,101,53,120,1205)
# several arguments are tied for max digit sum of 8, so the one
# appearing earliest is returned, 53
Out[4]:
53

Problem 3: Decorator to require a return value

In Python, a function that doesn't return a value implicitly returns the value None.

Make a decorator called returns_something that checks to make sure a function returns a value that is not equal to None. If the function it decorates attempts to return None, an exception should be raised.

Put this function in a file called quiz4prob3.py and submit it.

Here is an example of defining two functions without the decorator:

In [10]:
def sum_plus_six(x,y):
    """Compute sum of x, y, and 6"""
    return x+y+6

def calculate_but_no_return(x,y):
    """Do some arithmetic, but don't return anything"""
    s = x+y

Here is the way the functions behave when defined without the decorator:

In [11]:
sum_plus_six(5,8)
Out[11]:
19
In [12]:
calculate_but_no_return(11,94)
# No error will result, but no return value is obtained, either.

Now, here are the same functions defined with the decorator you have been asked to write applied to them.

In [5]:
# MCS 275 Quiz 4 Problem 3
# Jennifer Vaccaro
# I wrote this code in accordance with the rules defined in the syllabus.

def returns_something(f):
    """Decorator for ensuring that a function returns a non-None value"""
    def inner(*args, **kwargs):
        """Inner function calls f with given arguments, 
        raises an Exception if the output==None, and returns 
        the output otherwise"""
        ret = f(*args, **kwargs) # Save as a variable so f only gets called once
        if ret == None:
            raise Exception("Function must return something!")
        return ret
    return inner
In [6]:
@returns_something
def sum_plus_six(x,y):
    """Compute sum of x, y, and 6"""
    return x+y+6

@returns_something
def calculate_but_no_return(x,y):
    """Do some arithmetic, but don't return anything"""
    s = x+y

Here is the expected behavior of the functions with the decorator applied:

In [7]:
sum_plus_six(5,8)
Out[7]:
19
In [8]:
calculate_but_no_return(11,94)
# RUNNING THIS SHOULD RAISE AN EXCEPTION
# because calculate_but_no_return tries to return None
# and the decorator won't allow that.

# We don't include the exception here, because the traceback
# shows the source code of the decorator, which is what you 
# need to write!
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-8-f5c3e81dddee> in <module>
----> 1 calculate_but_no_return(11,94)
      2 # RUNNING THIS SHOULD RAISE AN EXCEPTION
      3 # because calculate_but_no_return tries to return None
      4 # and the decorator won't allow that.
      5 

<ipython-input-5-25cb7c35c2c0> in inner(*args, **kwargs)
     11         ret = f(*args, **kwargs) # Save as a variable so f only gets called once
     12         if ret == None:
---> 13             raise Exception("Function must return something!")
     14         return ret
     15     return inner

Exception: Function must return something!