Functional Programming – Python Exercise

Learning Goals

  • Software design approaches and patterns, to identify reusable solutions to commonly occurring problems
  • Apply an appropriate software development approach according to the relevant paradigm (for example object oriented, event driven or procedural)

Programs Used

Apples Exercises

Create a new python project using the following code:

from enum import Enum
import datetime


class Colour(Enum):
    RED = "Red"
    YELLOW = "Yellow"
    GREEN = "Green"


class Apple:
    def __init__(self, colour, date_picked, best_before):
        self.colour = colour
        self.date_picked = date_picked
        self.best_before = best_before


apples = [Apple(Colour.RED, datetime.datetime(2023, 3, 8), datetime.datetime(2023, 5, 4)),
          Apple(Colour.RED, datetime.datetime(2023, 2, 10), datetime.datetime(2023, 6, 20)),
          Apple(Colour.RED, datetime.datetime(2023, 1, 7), datetime.datetime(2023, 4, 18)),
          Apple(Colour.YELLOW, datetime.datetime(2023, 3, 25), datetime.datetime(2023, 5, 11)),
          Apple(Colour.YELLOW, datetime.datetime(2023, 2, 23), datetime.datetime(2023, 4, 16)),
          Apple(Colour.GREEN, datetime.datetime(2023, 2, 12), datetime.datetime(2023, 3, 7)),
          Apple(Colour.GREEN, datetime.datetime(2023, 2, 9), datetime.datetime(2023, 5, 9)),
          Apple(Colour.GREEN, datetime.datetime(2023, 3, 1), datetime.datetime(2023, 4, 10))]

print(apples)

List comprehension

Start by printing the list of apples. As you can see, it prints information about each apple such as object location. For the purposes of this exercise, we would like to see more detail about the apples themselves.

To do so let’s create a new method on the apple class:

  • Create a new function inside the apple class called get_summary
  • Make it return "Colour: {self.colour}, Date picked: {self.date_picked}, Best before: {self.best_before}"
  • Iterate over all apples and print get_summary for each apple.
  • Extract this to a function called print_apple_summary.

Now we have the ability to print a nicely formatted list of apples.

Lambda functions

  • Print a new list of apples sorted by their best before date
  • Print a new list of apples that are green
  • Print a new list of apples picked in February
  • Print a new list of red apples that are picked in February
  • Print a new list of apples containing only apples where the colour contains the letter “e”

List comprehension

  • If your initial get_summary function used a for loop, update this function to use list comprehension.
  • Using list comprehension, print a new list of apples if the apple was picked on a Wednesday

A “Functional” Gilded Rose

There is an established refactoring exercise called The Gilded Rose. We have made a slightly custom version of the exercise for you to complete. The original version is here.

Firstly, fork and clone the starter repo here to your machine and follow the instructions in the README. Your task is to follow a functional approach for rewriting the code. The requirements for the Gilded Rose can be found in your repo in the file gilded_rose_requirements.md.

The repository includes a “golden master” test, which is a simple snapshot test to check that your refactor hasn’t broken anything. It also includes a simple example test that can be used as a pattern if you want to implement more targeted unit tests. The initial version of the example test has been written to fail, so you will need to fix that.

You can run the tests with poetry run pytest.

Things you might want to consider improving:

  • The structure of the Gilded Rose class is very OOP currently, how could we convert that to be fundamentally more functional?
    • E.g. could we convert the update_quality function to be a “pure” function?
    • This may require changing the tests to follow the new pattern
  • Could we split up the handling of the quality & sell_in properties to be separate?
  • Could we reduce (or even eliminate!) any “assignment” operations (x = y) where state is being handled?
  • Could we split the logic to be more readable?