pythonenumspython-3.4

Python Enum, when and where to use?


Python 3.4.0 introduced enum, I've read the doc but still don't know the usage of it. From my perspective, enum.Enum is an extended namedtuple type, which may not be true. So these are what I want to know about Enum:

  1. When and where to use Enum?
  2. Why do we need Enum? What are the advantages?
  3. What exactly is an Enum?

Solution

  • 1. When and where to use enums?

    For example, the days of the week:

    class Weekday(Enum):
        MONDAY = 1
        TUESDAY = 2
        WEDNESDAY = 3
        THURSDAY = 4
        FRIDAY = 5
        SATURDAY = 6
        SUNDAY = 7
    

    2. Why do we need enum? What are the advantages?

    For example, as anyone who has worked with the datetime module knows, datetime and date have two different representations for the days of the week: 0-6 or 1-7. Rather than keep track of that ourselves we can add a method to the Weekday enum to extract the day from the datetime or date instance and return the matching enum member:

        @classmethod
        def from_date(cls, date):
            return cls(date.isoweekday())
    

    3. What exactly is Enum?

    FederalHoliday is my most complex; it uses this recipe, and has methods to return the actual date the holiday takes place on for the year given, the next business day if the day in question is a holiday (or the range of days skipped includes the holiday or weekends), and the complete set of dates for a year. Here it is:

    class FederalHoliday(AutoEnum):
        NewYear = "First day of the year.", 'absolute', Month.JANUARY, 1
        MartinLutherKingJr = "Birth of Civil Rights leader.", 'relative', Month.JANUARY, Weekday.MONDAY, 3
        President = "Birth of George Washington", 'relative', Month.FEBRUARY, Weekday.MONDAY, 3
        Memorial = "Memory of fallen soldiers", 'relative', Month.MAY, Weekday.MONDAY, 5
        Independence = "Declaration of Independence", 'absolute', Month.JULY, 4
        Labor = "American Labor Movement", 'relative', Month.SEPTEMBER, Weekday.MONDAY, 1
        Columbus = "Americas discovered", 'relative', Month.OCTOBER, Weekday.MONDAY, 2
        Veterans = "Recognition of Armed Forces service", 'relative', Month.NOVEMBER, 11, 1
        Thanksgiving = "Day of Thanks", 'relative', Month.NOVEMBER, Weekday.THURSDAY, 4
        Christmas = "Birth of Jesus Christ", 'absolute', Month.DECEMBER, 25
    
        def __init__(self, doc, type, month, day, occurrence=None):
            self.__doc__ = doc
            self.type = type
            self.month = month
            self.day = day
            self.occurrence = occurrence
    
        def date(self, year):
            "returns the observed date of the holiday for `year`"
            if self.type == 'absolute' or isinstance(self.day, int):
                holiday =  Date(year, self.month, self.day)
                if Weekday(holiday.isoweekday()) is Weekday.SUNDAY:
                    holiday = holiday.replace(delta_day=1)
                return holiday
            days_in_month = days_per_month(year)
            target_end = self.occurrence * 7 + 1
            if target_end > days_in_month[self.month]:
                target_end = days_in_month[self.month]
            target_start = target_end - 7
            target_week = list(xrange(start=Date(year, self.month, target_start), step=one_day, count=7))
            for holiday in target_week:
                if Weekday(holiday.isoweekday()) is self.day:
                    return holiday
    
        @classmethod
        def next_business_day(cls, date, days=1):
            """
            Return the next `days` business day from date.
            """
            holidays = cls.year(date.year)
            years = set([date.year])
            while days > 0:
                date = date.replace(delta_day=1)
                if date.year not in years:
                    holidays.extend(cls.year(date.year))
                    years.add(date.year)
                if Weekday(date.isoweekday()) in (Weekday.SATURDAY, Weekday.SUNDAY) or date in holidays:
                    continue
                days -= 1
            return date
    
        @classmethod
        def year(cls, year):
            """
            Return a list of the actual FederalHoliday dates for `year`.
            """
            holidays = []
            for fh in cls:
                holidays.append(fh.date(year))
            return holidays
    

    Notes: