我可以为我的枚举的两个不同成员使用一个别名吗
Can I have one alias for two distinct members of my enum
我真诚地希望,我遵守了所有规则和准则,并且我的 question/problem 足够全面,可以找到合适的答案。首先,一个小介绍:
对于我当前的项目,我想为树节点对象指定特定类型。为了简单起见,我将使用颜色作为类比。
我有什么
假设我有以下枚举,派生自 enum
标准库:
from enum import Enum, auto
class Colour(Enum):
CRIMSON = auto()
SCARLET = auto()
RED = auto()
BLUE = auto()
所以每个成员都有不同的价值。
我想要的
到目前为止,还不错。但我 喜欢 的是:
class Colour(Enum):
CRIMSON = auto()
SCARLET = auto()
# RED = CRIMSON or SCARLET
BLUE = auto()
因此,如果我有一个具有如下属性的对象:
>>> r = Colour.SCARLET
我想要以下语句 return True
:
>>> type(r) is Colour
True
>>> r is Colour.SCARLET
True
>>> r is Colour.RED
True
当然这应该是 False
:
>>> r is Colour.CRIMSON
False
>>> r is Colour.BLUE # obviously False...
False
请注意,在我的情况下,不需要能够分配类型 RED
,只需分配 CRIMSON
或 SCARLET
就足够了。
我目前(不满意)的解决方案
到目前为止我尝试的是以下内容:
class Colour(Enum):
# ... member definitions ...
def isRed(self):
return self is Colour.SCARLET or self is Colour.CRIMSON
但我觉得这个解决方案相当不优雅,而且使用起来很麻烦。它也没有将 CRIMSON
和 SCARLET
的性质反映为 RED
.
的阴影
我实施的另一个解决方案涉及子调用或嵌套 Colour
但在任何一种情况下我都无法满足上述所有标准,因此我没有在此处发布这些。
在使用枚举之前,我用整数表示每个节点的 Node.colour
属性:
# trees.py
# defining global constants
SCARLET = 1
CRIMSON = 2
BLUE = -1
class Node:
def __init__(self, parent, children, col):
self.parent = parent
self.children = children
self.colour = col # either 1, 2 or -1
所以我可以执行以下操作:
>>> x = Node(None, None, SCARLET)
>>> y = Node(None, None, BLUE)
>>> If x.colour is > 0:# do stuff...
但我发现这种方式非常不符合 Python 规范,而且也很不直观,因为对 RED
、SCARLET
、BLUE
等的测试经常发生,这使得代码更难一些阅读。
如果我认为没有必要,也不应该使用 int
数据类型,因为这些“颜色”没有自然顺序或其他类似 int
的属性。
为了确保我理解:
Colour.SCARLET is Color.RED
Colour.CRIMSON is color.RED
但是
Colour.SCARLET is not Colour.CRIMSON
?
如果那是正确的,那么不,你不能拥有那个。原因是 is
是对象标识,没有变通方法或技巧可以愚弄它。这是 Python 固有的,不特定于枚举。
SCARLET
和 CRIMSON
可以作为 RED
的别名吗?或者它们是否具有独特的属性,其中之一是红色阴影?
可能对您有用的东西(使用 aenum
library 显示,但使用 stdlib Enum 稍微多一点工作就可以做到):
from aenum import Enum, auto
class PrimaryColour(Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
class Shades(Enum):
#
_init_ = 'value primary'
#
CRIMSON = PrimaryColour.RED
SCARLET = PrimaryColour.RED
并在使用中:
>>> list(Shades)
[<Shades.CRIMSON: 1>, <Shades.SCARLET: 2>]
>>> Shades.CRIMSON.primary is PrimaryColour.RED
True
另一种可能性:
from enum import Enum, auto
class Colour(Enum):
#
RED = auto()
GREEN = auto()
BLUE = auto()
CRIMSON = RED
SCARLET = RED
AQUAMARINE = GREEN, BLUE
#
def is_colour(self, colour):
return colour._value_ in self.ancestors or self._value_ in colour.ancestors
#
def __new__(cls, *values):
members = list(cls)
used_values = {m.value: m for m in members}
# previous values are now in used_values; after isolating first
# value, check if it has already been used
first, *others = values
if first in used_values:
# it's an alias -- create a new value
others = (first, ) + tuple(others)
first = len(members) + 1
member = object.__new__(cls)
member._value_ = first
member.ancestors = (first, ) + tuple(others) # always it's own ancestor
return member
并在使用中:
>>> list(Colour)
[<Colour.RED: 1>, <Colour.GREEN: 2>, <Colour.BLUE: 3>, <Colour.CRIMSON: 4>, <Colour.SCARLET: 5>, <Colour.AQUAMARINE: 6>]
>>> Colour.RED
<Colour.RED: 1>
>>> Colour.CRIMSON
<Colour.CRIMSON: 4>
>>> Colour.AQUAMARINE
<Colour.AQUAMARINE: 6>
>>> Colour.CRIMSON.is_colour(Colour.RED)
True
>>> Colour.RED.is_colour(Colour.CRIMSON)
True
>>> Colour.CRIMSON.is_colour(Colour.SCARLET)
False
我真诚地希望,我遵守了所有规则和准则,并且我的 question/problem 足够全面,可以找到合适的答案。首先,一个小介绍:
对于我当前的项目,我想为树节点对象指定特定类型。为了简单起见,我将使用颜色作为类比。
我有什么
假设我有以下枚举,派生自 enum
标准库:
from enum import Enum, auto
class Colour(Enum):
CRIMSON = auto()
SCARLET = auto()
RED = auto()
BLUE = auto()
所以每个成员都有不同的价值。
我想要的
到目前为止,还不错。但我 喜欢 的是:
class Colour(Enum):
CRIMSON = auto()
SCARLET = auto()
# RED = CRIMSON or SCARLET
BLUE = auto()
因此,如果我有一个具有如下属性的对象:
>>> r = Colour.SCARLET
我想要以下语句 return True
:
>>> type(r) is Colour
True
>>> r is Colour.SCARLET
True
>>> r is Colour.RED
True
当然这应该是 False
:
>>> r is Colour.CRIMSON
False
>>> r is Colour.BLUE # obviously False...
False
请注意,在我的情况下,不需要能够分配类型 RED
,只需分配 CRIMSON
或 SCARLET
就足够了。
我目前(不满意)的解决方案
到目前为止我尝试的是以下内容:
class Colour(Enum):
# ... member definitions ...
def isRed(self):
return self is Colour.SCARLET or self is Colour.CRIMSON
但我觉得这个解决方案相当不优雅,而且使用起来很麻烦。它也没有将 CRIMSON
和 SCARLET
的性质反映为 RED
.
我实施的另一个解决方案涉及子调用或嵌套 Colour
但在任何一种情况下我都无法满足上述所有标准,因此我没有在此处发布这些。
在使用枚举之前,我用整数表示每个节点的 Node.colour
属性:
# trees.py
# defining global constants
SCARLET = 1
CRIMSON = 2
BLUE = -1
class Node:
def __init__(self, parent, children, col):
self.parent = parent
self.children = children
self.colour = col # either 1, 2 or -1
所以我可以执行以下操作:
>>> x = Node(None, None, SCARLET)
>>> y = Node(None, None, BLUE)
>>> If x.colour is > 0:# do stuff...
但我发现这种方式非常不符合 Python 规范,而且也很不直观,因为对 RED
、SCARLET
、BLUE
等的测试经常发生,这使得代码更难一些阅读。
如果我认为没有必要,也不应该使用 int
数据类型,因为这些“颜色”没有自然顺序或其他类似 int
的属性。
为了确保我理解:
Colour.SCARLET is Color.RED
Colour.CRIMSON is color.RED
但是
Colour.SCARLET is not Colour.CRIMSON
?
如果那是正确的,那么不,你不能拥有那个。原因是 is
是对象标识,没有变通方法或技巧可以愚弄它。这是 Python 固有的,不特定于枚举。
SCARLET
和 CRIMSON
可以作为 RED
的别名吗?或者它们是否具有独特的属性,其中之一是红色阴影?
可能对您有用的东西(使用 aenum
library 显示,但使用 stdlib Enum 稍微多一点工作就可以做到):
from aenum import Enum, auto
class PrimaryColour(Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
class Shades(Enum):
#
_init_ = 'value primary'
#
CRIMSON = PrimaryColour.RED
SCARLET = PrimaryColour.RED
并在使用中:
>>> list(Shades)
[<Shades.CRIMSON: 1>, <Shades.SCARLET: 2>]
>>> Shades.CRIMSON.primary is PrimaryColour.RED
True
另一种可能性:
from enum import Enum, auto
class Colour(Enum):
#
RED = auto()
GREEN = auto()
BLUE = auto()
CRIMSON = RED
SCARLET = RED
AQUAMARINE = GREEN, BLUE
#
def is_colour(self, colour):
return colour._value_ in self.ancestors or self._value_ in colour.ancestors
#
def __new__(cls, *values):
members = list(cls)
used_values = {m.value: m for m in members}
# previous values are now in used_values; after isolating first
# value, check if it has already been used
first, *others = values
if first in used_values:
# it's an alias -- create a new value
others = (first, ) + tuple(others)
first = len(members) + 1
member = object.__new__(cls)
member._value_ = first
member.ancestors = (first, ) + tuple(others) # always it's own ancestor
return member
并在使用中:
>>> list(Colour)
[<Colour.RED: 1>, <Colour.GREEN: 2>, <Colour.BLUE: 3>, <Colour.CRIMSON: 4>, <Colour.SCARLET: 5>, <Colour.AQUAMARINE: 6>]
>>> Colour.RED
<Colour.RED: 1>
>>> Colour.CRIMSON
<Colour.CRIMSON: 4>
>>> Colour.AQUAMARINE
<Colour.AQUAMARINE: 6>
>>> Colour.CRIMSON.is_colour(Colour.RED)
True
>>> Colour.RED.is_colour(Colour.CRIMSON)
True
>>> Colour.CRIMSON.is_colour(Colour.SCARLET)
False