Проблема, похоже, заключалась в том, что нескольким библиотекам, таким как pandas и json, трудно сериализовать объекты enum.В Интернете я нашел несколько решений, объясняющих, как написать собственный сериализатор.Однако, поскольку я не могу сказать Spyder или Pandas использовать этот сериализатор, мне нужно что-то другое.
Поработав немного больше, я нашел два подхода, которые решили мою проблему.К сожалению, решение с использованием Enums не работает с Python 2.7, что является обязательным требованием для моего проекта.Таким образом, я объясню и то, и другое.
Python 3.4:
Я добавил типы данных своих значений в качестве миксина для моего класса Enum и аннотировал назначение моего enumзначения как предложено здесь .Специально для использования с фреймами данных мне также нужно было сделать объекты enum сопоставимыми, что я и сделал, определив методы сравнения.Наконец, передайте значения Enum в конструктор для моих сложных объектов.Это устраняет необходимость доступа к свойствам через атрибут value.
class Grammar(str, Enum):
VERB: str = 'verb'
NOUN: str = 'noun'
def __eq__(self, other):
return not self < other and not other < self
# END __eq__
def __ne__(self, other):
return self < other or other < self
# END __ne__
def __gt__(self, other):
return other < self
# END __gt__
def __ge__(self, other):
return not self < other
# END __ge__
def __le__(self, other):
return not other < self
# END __le__
def __lt__(self, other):
return self.value < other.value
# END __lt__
def __hash__(self):
return hash(self.value)
# END __hash__
# END Grammar
class _Word(dict):
def __init__(self, name, meta):
self['name'] = name
self['meta'] = meta
# END __init__
# END _Word
class Word(dict, Enum):
TYPE_A: dict = _Word('foo', Grammar.VERB)
TYPE_B: dict = _Word('bar', Grammar.NOUN)
def __init__(self, _word):
self['name'] = _word['name']
self['meta'] = _['meta']
# END __init__
def __eq__(self, other):
return not self < other and not other < self
# END __eq__
def __ne__(self, other):
return self < other or other < self
# END __ne__
def __gt__(self, other):
return other < self
# END __gt__
def __ge__(self, other):
return not self < other
# END __ge__
def __le__(self, other):
return not other < self
# END __le__
def __lt__(self, other):
return self['name'] < other['name']
# END __lt__
def __hash__(self):
return hash(self['name'])
# END __hash__
# END Word
Это позволило Spyder обрабатывать мое перечисление без каких-либо проблем.В качестве бонуса, при использовании объекта с фреймом данных или при сериализации как json, представления общего объекта теперь заменяются фактическими значениями.Это очень упрощает жизнь!
Python 2.7: К сожалению, реализация Enum для Python 2.7 не поддерживает весь синтаксис, необходимый для работы моего первого решения.В частности, аннотированное назначение VERB: str = 'verb'
не допускается.Я закончил тем, что прекратил использование Enums и переключился на атрибуты класса.Это по-прежнему позволяет получить доступ таким образом, чтобы было ясно, что вы имеете дело с константой (например, Grammar.VERB
), но это означает, что вы теряете приятные возможности Enum.
Самым важным для меня было то, чтобы я мог выполнять итерацию по моим значениям перечисления, поэтому я создал функцию, которая позволяет мне извлекать все значения из моего псевдо-перечисления:
class PseudoEnum():
@classmethod
def getAll(cls):
"""
Returns a list of tuples representing all entries for this PseudoEnum along the dimensions key x value. This is useful when you need to iterate over the enum.
:returns: A list of all PseudoEnum entries
:rtype: list of tuple
"""
return [(i, getattr(cls, i)) for i in dir(cls) if not i.startswith('__') and not callable((getattr(cls, i)))]
# END getAll
# END PseudoEnum
Grammar
и Word
теперь наследуются от PseudoEnum
.Кроме того, методы сравнения изменились с Word
до _Word
.Grammar
больше не нуждается в методах сравнения, так как он имеет дело с обычными строками.
Извиняюсь за длинный ответ.Надеюсь, это поможет!