Питонический дизайн без перечислений

Было несколько вопросов о том, как реализовать перечисления в Python. Большинство решений в конечном итоге более или менее эквивалентны примерно так:

class Animal:
    DOG=1
    CAT=2

Другие предлагают более сложные способы построения перечислений, но, как правило, они выглядят как этот пример, когда все сказано и сделано.

Основываясь на моем опыте работы на Java и С#, я могу думать обо всех видах использования для такой идиомы. Однако, похоже, это не очень Pythonic. На самом деле, кажется, что каждый раз, когда кто-то спрашивает, почему в Python нет перечислений, вы, как правило, получаете немного стона с законченными ответами о том, как нет причин попробовать и обеспечить безопасность типа времени компиляции на языке, таком как Python, или как проекты, которые требуют перечислений, являются плохими запахами в Python.

Мой вопрос заключается не в том, как реализовать перечисления в Python, а в том, как в целом люди подходят к решениям проблем, которые поддаются перечислениям на языке Pythonic. Другими словами, как бы вы решили проблему, которая поддается типу данных с дискретным набором возможных значений без переноса вашего решения Java/С# на Python.

Ответ 1

PEP 435 был только что принят, который добавляет пакет перечисления в стандартную библиотеку вместе с классом Enum и другими производными, такими как IntEnum. Это означает, что, начиная с Python 3.4, "pythonic" способ использования перечислений в дизайне относится к этому пакету. Он будет выглядеть примерно так:

>>> from enum import Enum
>>> class Color(Enum):
...    red = 1
...    green = 2
...    blue = 3

>>> print(Color.red)
Color.red

>>> print(Color.red.name)
red

>>>> for color in Color:
....     print(color)
Color.red
Color.green
Color.blue

Ключевая особенность этого дизайна заключается в том, что ключи могут отклонять сравнение, где это не имеет смысла (в отличие от строковых ключей, предложенных в других ответах), позволяют клавишам иметь довольно печатную информацию, не связанную с ключевым значением, а также ключевые свойства специальных свойств, определяя методы подкласса Enum, в дополнение к свойству бросать явную и понятную ошибку, если пользователь попытается использовать недопустимый ключ из класса Enum.

Ответ 2

Так как строки Python являются неизменяемыми (и Python ставит их по мере необходимости), на самом деле нет особого преимущества в использовании числовых перечислений для множеств вещей. Вместо этого вы можете просто использовать строки frozenset или tuple (в зависимости от того, заботитесь ли вы о заказе).

Если, с другой стороны, то, о чем вы заботитесь, - это пространство имен, что делает атрибуты объектов класса очень хорошими.

Как упоминалось в комментариях, если вы ищете что-то вроде реализации конечного автомата, первоклассные функции - ваш друг.

Ответ 3

Не имея опыта С# или Java, я все еще не совсем понимаю этот интерес к перечислениям.

Из того, что я понимаю, я, вероятно, вернусь к стилю django, поместив любые необходимые константы в файл настроек и импортируя там, где это необходимо.

settings.py/animals.py

DOG = 1
CAT = 2

другой файл:

from animals import CAT, DOG

или даже...

settings.py

ANIMALS = { "DOG": 1, "CAT": 2}

другой файл:

from settings import ANIMALS

my_animal = "FROG"
if my_animal not in ANIMALS.keys():
    print "new species discovered!"

Ответ 4

Я не верю в Enums в С#. Для State-Machine у ​​вас есть шаблон стратегии. Вместо того, чтобы смотреть на состояние объекта и решать, что делать. Инкапсулируйте логику того, что делать в самом объекте.

Это естественный подход в Python, и введение перечислений для меня просто поощряет плохой код.