Enum — наименее используемая фича Python. Как программисты, мы предпочитаем использовать странные словари (дикты) или списки там, где могли бы использовать enum. По большей части это происходит из‑за того, что это довольно новая фича, и требуется использовать внешнюю библиотеку обратной совместимости, если используется Python версии 2.7. Тем не менее довольно много случаев, когда использовать enum гораздо удобнее.
В любом проекте на Python легко найти код, который делает проверки против строковых литералов. Подобные конструкции используются для определения типов постов, ролей клиентов и тому подобного. Конечно, этот код меняется со временем — меняется набор используемых строковых литералов. Это делает такой код трудноподдерживаемым и труднотестируемым.
К примеру, у нас есть такой код:
if a.type == 'article':
do_something_if_article(a)
elif a.type == 'review':
do_something_if_review(a)
else:
do_something()
С ним всё в порядке? Не совсем. Что, если мы решим поменять имя типа с "review" на "reviews"? В этом случае вместо вызова do_something_if_review() мы вызовем do_something(). К тому же этот код не так‑то легко модифицировать: имя типа может быть использовано в множестве мест в разных контекстах. Можно ли код улучшить? Легко!
ARTICLE_TYPE = 'article'
REVIEW_TYPE = 'review'
if a.type == ARTICLE_TYPE:
do_something_if_article(a)
elif a.type == REVIEW_TYPE:
do_something_if_review(a)
else:
do_something()
Теперь мы используем константы вместо строковых литералов — так намного лучше. Мы сократили места, где в случае смены имени типа потребуется редактирование, до одного. Но это никак не решило проблему добавления нового типа: нам потребуется добавить ещё одну ветку elif. Надо что‑то ещё улучшить.
Подобный код можно существенно улучшить с помощью enum:
from enum import Enum
class PostType(Enum):
ARTICLE = do_something_if_article
REVIEW = do_something_if_review
OTHER = do_something
@classmethod
def of(cls, type_name):
return getattr(cls, type_name.upper(), cls.OTHER)
def do_stuff(self):
return self.value()
PostType.of(a.type).do_stuff()
Это уже выглядит прилично. К тому же такой код гораздо гибче предыдущих вариантов. Я уверен, в ваших проектах есть множество мест, где подобный подход сильно улучшит качество кода. И у вас нет оправданий не пойти и не поправить эти места!
P.S. pip install enum34 — для Python 2.7.