Key Word(s): Python, closures, decorators



Exercise 1: Closures

In this problem, you will write a closure to make writing messages easier. Suppose you write the following message all the time:

print("The correct answer is: {0:17.16f}".format(answer))

Wouldn't it be nicer to just write

correct_answer_is(answer)

and have the message? Your task is to write a closure to accomplish that. Here's how everything should work:

correct_answer_is = my_message(message)
correct_answer_is(answer)

The output should be: The correct answer is: 42.0000000000000000.

Now change the message to something else. Notice that you don't need to re-write everything. You simply need to get a new message function from my_message and invoke your new function when you want to.

You should feel free to modify this in any way you like. Creativity is encouraged!

Deliverables

  • L5E1.py

Exercise 2: Decorators

In this problem, you will write a decorator to count how many times a function is accessed.

Suppose you have a function that is used all the time and you wish to figure out how much it is called. Note that this could go hand-in-hand with a code optimization to speed up performance. You can have a timing decorator (see lecture and homework) and a counting decorator to help you figure out what the offending function is and how bad the situation is.

Hints

  • The first thing to try would be to create a counter outside the inner function and then increment counter within the inner function. But this will fail because of encapsulation (see lecture notes and homework 2). One way to fix this is to use the nonlocal keyword like you will do in your homework.
  • Another way to solve this is to save the state of the inner function in a "method attribute". We haven't discussed this idea yet in lecture, but it could go something like this: 1.) Set inner_function.counter = 0 after declaring the inner function. Remember, the decorator will run this as soon as it is called. 2.) Inside the inner function, simply increment the attribute as usual (e.g. inner_function.counter += 1).

"Design" choices

  • The inner function should print out how many times the function has been called.
  • You will have to demo your output. This means that you will need to create a toy example to showcase how things work and that means you need to write a toy demo function. Write any function you like as long as it is useful.

Demo output

Here is a little demo. Suppose I have a function called distance() that computes the Euclidean distance from the origin of various tuples. In this example, the x- and y-coordinates are stored in separate lists and a tuple is comprised of an x-y pair. Those details are only so you can understand the little example to follow. It's okay if you don't perfectly follow the use-case.

The distance() function will be called multiple times (here demoed as a for loop).

xs = [1, 3, 5] # x-coordinates
ys = [-5, -3, 1] # y-coordinates
for x, y in zip(xs, ys):
    d = distance(x, y) # distance has been decorated (not shown here)

The output might be something like:

distance has been used: 1x
distance has been used: 2x
distance has been used: 3x

Deliverables

  • L5E2.py