Proposal to Modernize Python's 'sublist' Exercise with Enums

Hello everyone,

I’d like to propose an update to the Python sublist exercise to use the standard enum.Enum class for its constants. The current template is functional but I believe we can make it more robust, readable, and educational by adopting this modern Python feature.

Current Approach

The current sublist.py stub guides the user to define module-level constants, like so:

# sublist.py (current stub)
SUBLIST = None
SUPERLIST = None
EQUAL = None
UNEQUAL = None

def sublist(list_one, list_two):
    pass

The accompanying sublist_test.py then imports these constants directly:

# sublist_test.py (current)
from sublist import (
    sublist,
    SUBLIST,
    SUPERLIST,
    EQUAL,
    UNEQUAL,
)

class SublistTest(unittest.TestCase):
    def test_empty_lists(self):
        self.assertEqual(sublist([], []), EQUAL)
    # ... etc

While this works, it misses an opportunity to teach a more modern and safer approach. The stub file itself even links to the Wikipedia page for enumerated types, which makes Enum a natural fit.

Reasons for the Change

Moving to Enum offers several key advantages:

  1. Type Safety and Clarity : An Enum creates a distinct, new type. This makes the function signature for sublist far more descriptive and prevents accidental cross-comparison bugs. def sublist(...) -> ListRelation: is much clearer than def sublist(...) -> int: .
  2. Namespacing and Readability : It groups the related constants (SUBLIST , SUPERLIST , etc.) under a single, logical namespace (ListRelation ). This improves organization and makes the code easier to read.
  3. Bug Prevention : Using module-level variables can lead to subtle bugs. For example, a typo like UNEQAUL = 4 would create a new variable, and a test might pass or fail silently. With an Enum, ListRelation.UNEQAUL would immediately raise an AttributeError , making the error obvious and easy to fix.
  4. Teaching Modern Python : Enum has been a standard part of Python since version 3.4. Introducing it in an exercise like this is a great way to expose learners to powerful, idiomatic features of the language.

Proposed New Template

I suggest we update the sublist.py stub to the following:

# sublist.py (proposed new stub)
from enum import Enum

class ListRelation(Enum):
    """
    An enumeration to represent the relationship between two lists.
    """
    EQUAL = 1
    SUBLIST = 2
    SUPERLIST = 3
    UNEQUAL = 4

def sublist(list_one: list, list_two: list) -> ListRelation:
    """
    Determines if list_one is a sublist, superlist, or equal to list_two.
    """
    pass

This is cleaner and provides a much better starting point for the student.

Ensuring Backwards Compatibility

A major concern with changing a popular exercise is breaking the thousands of already-published community solutions. We can address this with a small, non-intrusive change to the test file.

By modifying sublist_test.py , we can make it compatible with both the old (module-level constants) and new (Enum ) approaches. The key is to try importing the Enum first and falling back to the old constants if it fails.

Here is a proposed change for the top of sublist_test.py :

# sublist_test.py (proposed new test setup)
import unittest
from sublist import sublist

# Try to import the modern Enum-based constants first.
# Fall back to the old module-level constants for backwards compatibility.
try:
    from sublist import ListRelation
    SUBLIST = ListRelation.SUBLIST
    SUPERLIST = ListRelation.SUPERLIST
    EQUAL = ListRelation.EQUAL
    UNEQUAL = ListRelation.UNEQUAL
except ImportError:
    from sublist import SUBLIST, SUPERLIST, EQUAL, UNEQUAL

class SublistTest(unittest.TestCase):
    # ... all test cases remain unchanged
    def test_empty_lists(self):
        self.assertEqual(sublist([], []), EQUAL)

This approach is fully backwards-compatible. Old solutions will cause the ImportError , and the test file will fall back to importing the constants as it does now. New solutions based on the Enum template will work seamlessly. No existing solutions will be broken.

This change would allow us to improve the exercise for future students while respecting the work of past contributors.

I look forward to hearing your thoughts on this proposal.

Best, Jegors

I assume “everyone” here means the track maintainer? @BethanyG is the only one whose opinion matters here :smiley:

1 Like

@IsaacG - as one of the most prolific mentors on the track (and a fan of this exercise, as I recall…) your opinion matters as well. :smile:

@rabestro - I appreciate your well-thought-out proposal. I do think the current implementation of this exercise is … kludgy.

I think I am leaning toward deprecating this current form of the exercise and reimplementing it in a more general fashion that could accommodate solutions with and without Enums. That way, no solutions are invalidated and we can move forward without baggage.

We generally don’t want to force a specific implementation for a practice exercise unless we have to — so I don’t know that I want this tied so tightly to Enums that using an Enum becomes the only way to pass the tests.

But the track also has a bunch of updates that need to get done to Python versions and tooling. Those take priority over re-writing this exercise.

So I think my conclusion here is … patience, please. We have noticed this is an awkward exercise, and we will move to depreciate and reimplement it. But it’s probably not going to happen soon. I need to think on it a while and get feedback from other track maintainers and mentors. I also want to take a look at what other tracks have done implementation-wise.

But thank you very much for your critique and suggestions!

5 Likes