thi*_*nck 5 python enums spyder
我正在使用一个基于图形的框架,该框架由多种类型的节点和关系组成。每种类型都有一些我希望能够轻松访问的元属性。为了表示这些类型,我认为枚举是最好的选择。
我对 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
Run Code Online (Sandbox Code Playgroud)
因此,我的每个 Word 值都分配了一个 _Word 对象,这是一个复杂类型。这在大多数使用 Enum 的情况下都可以正常工作。然而,我的同事指出,Spyder 在检查存在枚举实例的对象时抛出异常:(ValueError(): is not a valid Word注意冒号后面的空格)。
这让我认为我使用枚举的方式不是最佳实践。我错过了什么吗?
问题似乎是 pandas 和 json 等几个库很难序列化枚举对象。我在网上找到了几个解释如何编写自定义序列化器的解决方案。但是,由于我无法告诉 Spyder 或 Pandas 使用该序列化器,因此我需要一些不同的东西。
经过一番尝试后,我发现两种方法可以解决我的问题。不幸的是,使用 Enums 的解决方案不适用于 Python 2.7,这是我的项目的要求。因此,我将解释两者。
Python 3.4:
我将值的数据类型添加为枚举类的混合,并按照此处的建议注释枚举值的分配。特别是为了与数据帧一起使用,我还需要使我的枚举对象具有可比性,这是通过定义比较方法来实现的。最后将枚举值传递到复杂对象的构造函数中。这消除了通过 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
Run Code Online (Sandbox Code Playgroud)
这使得 Spyder 能够毫无问题地处理我的枚举。作为奖励,当将对象与数据帧一起使用或序列化为 json 时,通用对象表示现在将替换为实际值。这让生活变得非常轻松!
Python 2.7:
不幸的是,Python 2.7 的 Enum 实现并没有继承使我的第一个解决方案工作所需的所有语法。具体来说,VERB: str = 'verb'不允许带注释的赋值。我最终删除了枚举的使用并改用类属性。这仍然允许以明确您正在处理常量的方式进行访问(例如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
Run Code Online (Sandbox Code Playgroud)
Grammar现在Word继承自PseudoEnum. 此外,比较方法已从Word变为_Word。Grammar不再需要比较方法,因为它处理常规字符串。
对于冗长的答案表示歉意。希望这可以帮助!