'How to refer to subclasses in the superclass?

I am defining a Python Holiday class and three subclasses: one for fixed date holidays, a second for relative holidays, and a third for floating Monday holidays. I would like to create a set of constants in the superclass Holiday so that applications can simply refer to particular holidays as

Holiday.NEW_YEARS
Holiday.CHRISTMAS
etc.

but the subclasses obviously do not exist when the parent class is instantiated. How can I do this?

class Holiday(object):
    NEW_YEARS = FixedHoliday(1, 1)
    MLK_BIRTHDAY = FloatingMonday(1, 15)
    ...


Solution 1:[1]

One way to do it would be to decorate the base class after it and all the subclasses are defined. You can do this in Python because classes are mutable objects.

Here's what I'm suggesting:

class Holiday(object):
    def __init__(self, month, day):
        self.month, self.day = month, day

    def __repr__(self):
        return '{}(month={}, day={})'.format(type(self).__name__, self.month, self.day)

class FixedHoliday(Holiday):
    pass

class FloatingMonday(Holiday):
    pass


def inject_constants(cls):
    """ Add attributes to class. """
    HOLIDATA = {
        'NEW_YEARS': FixedHoliday(1, 1),
        'MLK_BIRTHDAY': FloatingMonday(1, 15)
    }

    for key, value in HOLIDATA.items():
        setattr(cls, key, value)

    return cls

Holiday = inject_constants(Holiday)


if __name__ == '__main__':
    print(Holiday.NEW_YEARS)    # -> FixedHoliday(month=1, day=1)
    print(Holiday.MLK_BIRTHDAY) # -> FloatingMonday(month=1, day=15)

Solution 2:[2]

A class can't and shouldn't refer to its derived classes. Try this instead:

class BaseHoliday(object):
    pass

class FixedHoliday(BaseHoliday):
    # class code

# more classes

class Holidays(object):
    NEW_YEARS = FixedHoliday(1, 1)
    MLK_BIRTHDAY = FloatingMonday(1, 15)

Solution 3:[3]

I guess this sort of workaround will be fine

class _holiday:
    payload: str


class Holiday:
    class NEW_YEARS(_holiday):
        ...

    class CHRISTMAS(_holiday):
        ...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 roeen30
Solution 3 Udith Amasura