Я в основном разработчик C #, но сейчас я работаю над проектом на Python.
Как я могу представить эквивалент Enum в Python?
источник
Я в основном разработчик C #, но сейчас я работаю над проектом на Python.
Как я могу представить эквивалент Enum в Python?
Перечисления были добавлены в Python 3.4, как описано в PEP 435 . Он также был перенесен в 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 и 2.4 на pypi.
Для более продвинутых техник Enum попробуйте библиотеку aenum (2.7, 3.3+, тот же автор, что и enum34
. Код не полностью совместим между py2 и py3, например, вам потребуется __order__
в python 2 ).
enum34
, сделать$ pip install enum34
aenum
, сделать$ pip install aenum
Установка enum
(без номеров) приведет к установке совершенно другой и несовместимой версии.
from enum import Enum # for enum34, or the stdlib version
# from aenum import Enum # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')
Animal.ant # returns <Animal.ant: 1>
Animal['ant'] # returns <Animal.ant: 1> (string lookup)
Animal.ant.name # returns 'ant' (inverse lookup)
или эквивалентно:
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
В более ранних версиях одним из способов выполнения перечислений является:
def enum(**enums):
return type('Enum', (), enums)
который используется так:
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
Вы также можете легко поддерживать автоматическое перечисление примерно так:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
и использовал вот так:
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
Поддержка преобразования значений обратно в имена может быть добавлена следующим образом:
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type('Enum', (), enums)
Это перезаписывает что-либо с таким именем, но это полезно для отображения ваших перечислений в выводе. Он выдаст KeyError, если обратное отображение не существует. С первым примером:
>>> Numbers.reverse_mapping['three']
'THREE'
**named
) в функции enum для более старых версий поддерживает пользовательские значения:enum("blue", "red", "green", black=0)
До PEP 435 у Python не было эквивалента, но вы могли реализовать свой собственный.
Сам я люблю быть простым (я видел несколько ужасно сложных примеров в сети), что-то вроде этого ...
В Python 3.4 ( PEP 435 ) вы можете сделать Enum базовым классом. Это дает вам немного дополнительной функциональности, описанной в PEP. Например, члены перечисления отличаются от целых и состоят из a
name
и avalue
.Если вы не хотите вводить значения, используйте следующий ярлык:
Enum
реализации могут быть преобразованы в списки и являются итеративными . Порядок его членов является порядком декларации и не имеет ничего общего с их значениями. Например:источник
object()
.Вот одна реализация:
Вот его использование:
источник
__setattr__(self, name, value)
и, возможно,__delattr__(self, name)
так, что, если вы случайно напишитеAnimals.DOG = CAT
, это не произойдет молча.Animals.DOG
; Кроме того, значения констант являются строками, поэтому сравнение с этими константами происходит медленнее, чем если бы, скажем, целые числа были разрешены в качестве значений.setattr()
функцию внутри__init__()
метода вместо__getattr__()
метода переопределения . Я предполагаю, что это должно работать так же: класс Enum (объект): def __init __ (self, enum_string_list): если тип (enum_string_list) == список: для enum_string в enum_string_list: setattr (self, enum_string, enum_string) else: повысить AttributeErrortry-except
блоке?Если вам нужны числовые значения, вот самый быстрый способ:
В Python 3.x вы также можете добавить помеченный заполнитель в конце, который впитает все оставшиеся значения диапазона, если вы не возражаете потратить память и не можете сосчитать:
источник
Лучшее решение для вас будет зависеть от того, что вы требуете от вашей подделки
enum
.Простое перечисление:
Если вам нужен
enum
только список имен, идентифицирующих различные предметы , решение от Mark Harrison (выше) будет отличным:Использование
range
также позволяет установить любое начальное значение :В дополнение к вышесказанному, если вам также требуется, чтобы элементы принадлежали к какому-либо контейнеру , вставьте их в класс:
Чтобы использовать элемент enum, вам теперь нужно будет использовать имя контейнера и имя элемента:
Комплексное перечисление:
Для длинных списков перечислений или более сложных применений перечислений этих решений будет недостаточно. Вы можете посмотреть на рецепт Уилла Уэра для имитации перечислений в Python, опубликованный в Python Cookbook . Онлайн версия этого доступна здесь .
Больше информации:
PEP 354. Перечисления в Python содержат интересные детали предложения enum в Python и причины его отклонения.
источник
range
вы можете опустить первый аргумент , если это 0my_enum = dict(map(reversed, enumerate(str.split('Item0 Item1 Item2'))))
. Затемmy_enum
может быть использован поиск, например,my_enum['Item0']
может быть индекс в последовательности. Возможно, вы захотите обернуть результатstr.split
в функцию, которая выдает исключение, если есть какие-либо дубликаты.Flag1, Flag2, Flag3 = [2**i for i in range(3)]
Тип enum типа safeafe, который использовался в Java pre-JDK 5, имеет ряд преимуществ. Как и в ответе Александру, вы создаете класс, а поля уровня класса являются значениями перечисления; однако значения enum являются экземплярами класса, а не маленькими целыми числами. Преимущество этого в том, что ваши значения перечисления не случайно сравниваются равными маленьким целым числам, вы можете контролировать способ их печати, добавлять произвольные методы, если это полезно, и делать утверждения, используя isinstance:
Недавняя ветка на python-dev указала, что есть несколько библиотек enum, в том числе:
источник
Класс Enum может быть однострочным.
Как его использовать (прямой и обратный поиск, ключи, значения, элементы и т. Д.)
источник
in
ключевое слово для поиска аккуратных участников. Пример использования:'Claimed' in Enum(['Unclaimed', 'Claimed'])
Итак, я согласен. Давайте не будем обеспечивать безопасность типов в Python, но я хотел бы защитить себя от глупых ошибок. Так что мы думаем об этом?
Это удерживает меня от столкновения ценностей при определении моих перечислений.
Есть еще одно полезное преимущество: очень быстрый обратный поиск:
источник
Animal = Enum('horse', 'dog', 'cat')
. Я также ловлю ValueError в getattr в случае отсутствия элемента в self.values - кажется, что вместо этого лучше вызвать AttributeError с предоставленной строкой имени. Я не мог заставить метакласс работать в Python 2.7, основываясь на моих ограниченных знаниях в этой области, но мой пользовательский класс Enum отлично работает с методами прямого экземпляра.Python не имеет встроенного эквивалента
enum
, а в других ответах есть идеи для реализации вашего собственного (вас также может заинтересовать версия over over в кулинарной книге Python).Однако в ситуациях, когда
enum
в C требуется вызов an , я обычно просто использую простые строки : из-за способа реализации объектов / атрибутов (C) Python в любом случае оптимизирован для очень быстрой работы с короткими строками, поэтому не будет никакого выигрыша в производительности при использовании целых чисел. Для защиты от опечаток / недопустимых значений вы можете вставить проверки в выбранных местах.(Одним из недостатков по сравнению с использованием класса является то, что вы теряете преимущество автозаполнения)
источник
2013-05-10, Гвидо согласился принять PEP 435 в стандартную библиотеку Python 3.4. Это означает, что Python наконец-то имеет встроенную поддержку перечислений!
Для Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 и 2.4 имеется бэкпорт. Это на Pypi как enum34 .
Декларация:
Представление:
Итерация:
Программный доступ:
Для получения дополнительной информации обратитесь к предложению . Официальная документация, вероятно, скоро появится.
источник
Я предпочитаю определять перечисления в Python так:
Это более устойчиво к ошибкам, чем использование целых чисел, поскольку вам не нужно беспокоиться о том, чтобы целые числа были уникальными (например, если вы сказали, что Dog = 1 и Cat = 1, то вас облажают)
Это более устойчиво к ошибкам, чем использование строк, так как вам не нужно беспокоиться об опечатках (например, x == "catt" завершается с ошибкой, но x == Animal.Catt является исключением времени выполнения).
источник
Используйте это так:
если вы просто хотите уникальные символы и не заботитесь о значениях, замените эту строку:
с этим:
источник
enum(names)
наenum(*names)
- тогда вы могли бы убрать лишние скобки при вызове.Начиная с Python 3.4 будет официальная поддержка перечислений. Вы можете найти документацию и примеры здесь на странице документации Python 3.4 .
источник
Хммм ... Полагаю, самым близким к перечислению был бы словарь, определяемый так:
или
Затем вы можете использовать символическое имя для констант, как это:
Существуют и другие варианты, например, список кортежей или кортеж кортежей, но единственный словарь, который предоставляет вам «символический» (постоянная строка) способ доступа к значению.
Редактировать: мне тоже нравится ответ Александру!
источник
Еще одна очень простая реализация перечисления в Python, использующая
namedtuple
:или, альтернативно,
Как и в методе выше, что подклассы
set
, это позволяет:Но обладает большей гибкостью, поскольку может иметь разные ключи и значения. Это позволяет
действовать, как ожидается, если вы используете версию, которая заполняет значения последовательных чисел.
источник
Что я использую:
Как пользоваться:
Так что это дает вам целочисленные константы, такие как state.PUBLISHED и два кортежа для использования в качестве выбора в моделях Django.
источник
Дэвидг рекомендует использовать диктовку. Я бы пошел еще дальше и использовал наборы:
Теперь вы можете проверить, соответствует ли значение одному из значений в наборе следующим образом:
как и dF, я обычно просто использую строковые константы вместо перечислений.
источник
Будь проще:
Затем:
источник
Это лучшее из того, что я видел: «Перечисления первого класса в Python»
http://code.activestate.com/recipes/413486/
Это дает вам класс, и класс содержит все перечисления. Перечисления могут сравниваться друг с другом, но не имеют какого-либо конкретного значения; Вы не можете использовать их как целочисленное значение. (Сначала я сопротивлялся этому, потому что я привык к C перечислениям, которые являются целочисленными значениями. Но если вы не можете использовать его как целое число, вы не можете использовать его как целое число по ошибке, поэтому в целом я думаю, что это выигрыш .) Каждое перечисление является уникальным значением. Вы можете печатать перечисления, вы можете перебирать их, вы можете проверить, что значение перечисления находится в перечислении. Это довольно полно и гладко.
Редактировать (cfi): ссылка выше не совместима с Python 3. Вот мой порт enum.py для Python 3:
источник
.__int__()
метод должен вызвать исключение для перечисления; но должен быть способ получить значение. И должно быть возможно установить конкретные целочисленные значения во время определения класса, чтобы вы могли использовать перечисление для таких вещей, как константы вstat
модуле.Мне приходилось нуждаться в классе Enum для декодирования двоичного формата файла. Возможности, которые мне понадобились, - это краткое определение перечисления, возможность свободно создавать экземпляры перечисления с помощью целочисленного значения или строки, а также полезная
repr
подсказка. Вот чем я закончил:Причудливый пример его использования:
Ключевая особенность:
str()
,int()
Иrepr()
все производят наиболее полезный выход можно соответственно название enumartion, его целое значение, и выражение , которое вычисляется на Python назад в перечислении.is
источник
__instancecheck__
метод. Классы не являются коллекциями экземпляров, поэтому1 in Fruit
это абсурд. Тем не менее, связанная версия поддерживает,isinstance(1, Fruit)
что было бы более правильным с точки зрения понятия классов и экземпляров.Новый стандарт в Python - PEP 435 , поэтому класс Enum будет доступен в следующих версиях Python:
Однако, чтобы начать использовать его сейчас, вы можете установить оригинальную библиотеку, которая мотивировала PEP:
Тогда вы можете использовать его в соответствии с его онлайн-руководством :
источник
Если вы его называете, это ваша проблема, но если вы не создаете объекты вместо значений, вы можете сделать это:
При использовании других реализаций, размещенных здесь (также при использовании именованных экземпляров в моем примере), вы должны быть уверены, что никогда не пытаетесь сравнивать объекты из разных перечислений. Ибо вот возможная ловушка:
Хлоп!
источник
Мне очень нравится решение Алекса Томаса (http://stackoverflow.com/a/1695250):
Это элегантный и чистый вид, но это просто функция, которая создает класс с указанными атрибутами.
С небольшой модификацией функции мы можем заставить ее действовать немного более enumy:
Это создает перечисление на основе указанного типа. В дополнение к предоставлению доступа к атрибутам, как и в предыдущей функции, он ведет себя так, как вы ожидаете от Enum относительно типов. Он также наследует базовый класс.
Например, целочисленные перечисления:
Еще одна интересная вещь, которую можно сделать с помощью этого метода, - это настроить конкретное поведение, переопределив встроенные методы:
источник
Пакет enum от PyPI обеспечивает надежную реализацию перечислений. В предыдущем ответе упоминалось PEP 354; это было отклонено, но предложение было реализовано http://pypi.python.org/pypi/enum .
Использование простое и элегантное:
источник
Предложение Александру об использовании констант класса для перечислений работает довольно хорошо.
Я также хотел бы добавить словарь для каждого набора констант для поиска удобочитаемого строкового представления.
Это служит двум целям: а) предоставляет простой способ красивой печати вашего перечисления и б) словарь логически группирует константы, чтобы вы могли проверить на членство.
источник
Вот подход с некоторыми другими характеристиками, которые я считаю ценными:
и самое главное предотвращает сравнения между перечислениями разных типов !
Основано на http://code.activestate.com/recipes/413486-first-class-enums-in-python .
Здесь представлено много документов для иллюстрации того, что отличает этот подход.
источник
Вот вариант решения Алекса Томаса :
источник
Это решение представляет собой простой способ получения класса для перечисления, определенного как список (больше не надоедливые целочисленные присваивания):
enumeration.py:
example.py:
источник
type(class_name, (object,), dict(...))
вместо этого?Хотя первоначальное предложение enum, PEP 354 , было отклонено несколько лет назад, оно продолжает возвращаться. Какой-то enum был предназначен для добавления в 3.2, но он был перенесен в 3.3, а затем забыт. И теперь есть PEP 435, предназначенный для включения в Python 3.4. Эталонная реализация PEP 435 есть
flufl.enum
.По состоянию на апрель 2013 года, по-видимому, существует общее согласие о том, что что- то должно быть добавлено в стандартную библиотеку в 3.4 - при условии, что люди могут договориться о том, каким должно быть это «что-то». Это сложная часть. Смотрите темы, начинающиеся здесь и здесь , и полдюжины других тем в первые месяцы 2013 года.
Между тем, каждый раз, когда это происходит, появляется множество новых проектов и реализаций в PyPI, ActiveState и т. Д., Поэтому, если вам не нравится дизайн FLUFL, попробуйте поиск PyPI .
источник
Используйте следующее.
Я использовал это для выбора модели Django , и это выглядит очень питонно. Это на самом деле не Enum, но он делает свою работу.
источник