Является ли хранение и доступ к функциям хорошим вариантом использования для Enum?

#python #python-3.x #enums

#python #python-3.x #перечисления

Вопрос:

Я использую классы Enum для явного отображения возможных значений аргумента. Это красиво и лаконично.

Однако, когда я обращаюсь к одному перечислению из другого, оно начинает выглядеть непитоническим : Functions[day.value].value . Тот факт, что мне нужно передать и получить атрибут value Enum, добавляет сложности.

Как можно переписать этот (вымышленный) код, чтобы использовать только одно перечисление и не нуждаться в доступе к value атрибуту?

 from datetime import datetime, timedelta
from enum import Enum


class Day(Enum):
    YESTERDAY = 'YESTERDAY'
    TODAY = 'TODAY'
    TOMORROW = 'TOMORROW'


def get_date(day: Day):
    class Functions(Enum):
        YESTERDAY = datetime.now()   timedelta(days=-1)
        TODAY = datetime.now()
        TOMORROW = datetime.now()   timedelta(days=1)
    return Functions[day.value].value.date()


today = get_date(Day.TODAY)
yesterday = get_date(Day.YESTERDAY)
tomorrow = get_date(Day.TOMORROW)
  

Комментарии:

1. Я бы не стал использовать enum для подобных динамических данных, обычный класс кажется более подходящим…

2. Вы делаете это, чтобы избежать if / else ? В python вы также можете использовать для этого dict return {Day.TODAY: datetime.now(), ...}.get(day) , который для меня выглядит более питоническим. Я также немного обеспокоен тем, что время / место объявления Functions enum влияет на его значения… но это может быть только я

Ответ №1:

Мне кажется, что вы пытаетесь реализовать switch оператор, которого нет в python. Наиболее распространенный способ, который я видел, используемый для выполнения такой задачи, — это dict :

 def get_date(day: Day):
    return {
        Day.YESTERDAY: datetime.now()   timedelta(days=-1),
        Day.TODAY: datetime.now(),
        Day.TOMORROW: datetime.now()   timedelta(days=1),
    }[day].date()
  

Обратите внимание, что я обращаюсь [day] напрямую, что может вызвать KeyError. Если вы хотите избежать этого, вы можете использовать get(day, default=datetime.now()) which по существу пытается получить доступ к ключу, и если он не существует, он возвращается datetime.now() .

Ответ №2:

Для Enum возможно иметь другие атрибуты, кроме name и value — например, date :

 from datetime import date, timedelta
from enum import Enum

class Day(Enum):
    YESTERDAY = 'YESTERDAY'
    TODAY = 'TODAY'
    TOMORROW = 'TOMORROW'
    #
    @property
    def date(self):
        today = date.today()
        return {
                'YESTERDAY': today   timedelta(days=-1),
                'TODAY': today,
                'TOMORROW': today   timedelta(days=1),
                }[self.value]
  

и используется:

 >>> Day.YESTERDAY
<Day.YESTERDAY: 'YESTERDAY'>

>>> Day.YESTERDAY.date
datetime.date(2020, 11, 9)

>>> Day.TODAY
<Day.TODAY: 'TODAY'>

>>> Day.TODAY.date
datetime.date(2020, 11, 10)

>>> Day.TOMORROW
<Day.TOMORROW: 'TOMORROW'>

>>> Day.TOMORROW.date
datetime.date(2020, 11, 11)
  

Раскрытие информации: я являюсь автором Python stdlib Enum , enum34 backport и расширенной библиотеки Enumeration ( aenum ).