Enums в Python
Опубликовано 17 February 2017 в Python
Enums наименее используемая фича Питона. Как программисты мы предпочитаем использовать странные дикты или списки там, где мы могли бы использовать enum. По большей части это происходит из-за того, что это довольно новая фича и требуется использовать внешнюю библиотеку обратной совместимости, если используется питон версии 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:
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
Возник вопрос? Мне всегда можно написать в Twitter: avkorablev