Питонический дизайн без перечислений
Было несколько вопросов о том, как реализовать перечисления в 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, и введение перечислений для меня просто поощряет плохой код.