有没有办法直接从枚举实例化类?

时间:2019-07-23 19:54:09

标签: python python-3.x class enums instance

我最近发现您可以在Python中使用枚举,但是我对我的代码的工作方式不满意,我想知道是否有更干净的方法来实现它。

from enum import Enum

class Hex:
    def __init__(self, hex_code: str):
        self.code = hex_code

class Rgb:
    def __init__(self, R: int, G: int, B: int):
        self.r = R
        self.g = G
        self.b = B

class Color(Enum):
    HEX = Hex
    RGB = Rgb

def main():
    hex_color = Color.HEX.value('#00FF00')
    rgb_color = Color.RGB.value(255, 255, 255)

if __name__ == "__main__":
    main()

在此示例中,我必须通过调用.value()枚举方法来实例化。但是当您正常实例化一个类时,您要做的只是Class(value)。是否有可能实现类似于具有类的枚举变量的东西? 例如:

Color.HEX('#00FF00')
# Instead of:
Color.HEX.value('#00FF00')

2 个答案:

答案 0 :(得分:3)

HEXRGB不是类;它们是Color实例。 (enum使用的元类会严重滥用class语句。)您可以使用这些实例的value属性来获取“分配”给这些名称的值。

为了使Color.HEX('#00ff00')返回类Hex的实例,您需要定义Color.__call__。 (顺便说一句,请注意,您可以在定义class的{​​{1}}语句内简单地定义两个类,而不是在外部定义它们。Color语句只是一个花哨的赋值语句,位于心脏。)

class

然后

from enum import Enum

class Color(Enum):
    class HEX:
        def __init__(self, hex_code: str):
            self.code = hex_code

    class RGB:
        def __init__(self, R: int, G: int, B: int):
            self.r = R
            self.g = G
            self.b = B

    def __call__(self, *args):
        return self.value(*args)

没有>>> Color.HEX('#00ff00') <__main__.Color.HEX object at 0x108740f28> 的继承值被覆盖,因此不需要立即在其定义中使用类似__call__的值。如果您认为需要支持多重继承,那可能会改变,但是考虑到super().__call__(*args)使用了自定义元类,我将声明处理此问题之外的内容。

答案 1 :(得分:1)

在您的问题中,我没有发现需要使用Enum或从中受益。

Check this,了解使用Enum的准则。

Enum确实提供了简单的成员资格测试,因此您可以这样做:

hex_value is rgb_value

hex_value in Color

使用aenum 1 库,您的代码如下所示:

from aenum import Enum, extend_enum

class Color(Enum):
    #
    def __new__(cls, value):
        member = object.__new__(cls)
        member._value_ = value
        member.hex = hex(value)[2:]
        r, value = divmod(value, 1 << 16)
        g, value = divmod(value, 1 << 8)
        b = value
        member.red = r
        member.green = g
        member.blue = b
        member.rgb = r, g, b
        return member
    #
    @classmethod
    def _missing_(cls, value):
        # r, g, b = value
        name = 'rgb:%r' % (value, )
        # name = 'rgb:%r' % ((r << 16) + (g << 8) + b, )
        extend_enum(cls, name, value)
        return cls[name]
    #
    @classmethod
    def from_hex(cls, value):
        # on leading #
        red = int(value[:2], 16)
        green = int(value[2:4], 16)
        blue = int(value[4:], 16)
        value = (red << 16) + (green << 8) + blue
        return cls(value)
    #
    @classmethod
    def from_rgb(cls, red, green, blue):
        value = (red << 16) + (green << 8) + blue
        return cls(value)
    #
    RED = 255 << 16
    GREEN = 255 << 8
    BLUE = 255

并在使用中:

>>> list(Color)
[<Color.RED: 16711680>, <Color.GREEN: 65280>, <Color.BLUE: 255>]

>>> Color.from_rgb(255, 0, 0)
<Color.RED: 16711680>

>>> Color.from_hex('00FF00')
<Color.GREEN: 65280>

>>> Color.from_hex('15A97F')
<Color.rgb:1419647: 1419647>

>>> Color.from_rgb(21, 169, 127)
<Color.rgb:1419647: 1419647>

>>> Color.from_hex('15A97F') is Color.from_rgb(21, 169, 127)
True

您当然可以更改repr()的详细信息,存储的属性(redgreenbluehex,{{ 1}}等。


1 披露:我是Python stdlib Enumenum34 backportAdvanced Enumeration (aenum)库的作者。