我正在使用基于图形的框架,该框架由几种类型的节点和关系组成。这些类型中的每一种都有一些我希望能够轻松访问的元属性。为了表示这些类型,我认为枚举将是最佳选择。
我对Python仍然比较陌生,但我知道来自其他语言的枚举,比如Java。我想这个问题真的归结为这是否很好地利用了Python中的枚举。我代表我的类型:
class Grammar(Enum):
VERB = 'verb'
NOUN = 'noun'
# END Grammar
class _Word():
def __init__(self, name, meta):
self.name = name
self.meta = meta
# END __init__
# END _Word
class Word(Enum):
TYPE_A = _Word('foo', Grammar.VERB)
TYPE_B = _Word('bar', Grammar.NOUN)
# END Word
因此,我的每个Word值都分配了一个_Word对象,这是一个复杂的类型。在使用Enum的大多数情况下,这种方法很好。但是,我的同事注意到Spyder在检查存在枚举实例的对象时抛出异常:ValueError(): is not a valid Word
(注意冒号后面的空格)。
这让我觉得我使用枚举的方式不是最好的做法。我错过了什么吗?
答案 0 :(得分:0)
问题似乎是像pandas和json这样的几个库很难序列化enum对象。我在网上找到了几个解释如何编写自定义序列化器的解决方案。但是,由于我不能告诉Spyder或Pandas使用该序列化器,我需要不同的东西。
在玩了一下之后,我发现了两种解决我问题的方法。不幸的是,使用Enums的解决方案不适用于Python 2.7,这是我的项目的要求。因此,我将解释两者。
Python 3.4:
我将我的值的数据类型添加为我的Enum类的mixin,并按建议here注释我的枚举值的赋值。特别是对于数据帧,我还需要使我的枚举对象具有可比性,我通过定义比较方法来做到这一点。最后将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:
不幸的是,Python 2.7的Enum实现并不包含使我的第一个解决方案工作所需的所有语法。具体而言,不允许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
不再需要比较方法,因为它处理常规字符串。
为漫长的回答道歉。希望这有帮助!