【问题标题】:Is there a way to instantiating a class directly from an Enum?有没有办法直接从枚举实例化一个类?
【发布时间】:2019-12-01 22:06:37
【问题描述】:

我最近发现你可以在 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')

【问题讨论】:

  • 不,必须从根本上改变enum 的工作方式。您在这里枚举的用例是什么?为什么不直接使用这些类?在任何情况下,value 不是一种方法,它只是枚举对象上的属性,它包含您提供给该枚举成员的 value
  • @chepner 我不确定 OP 是否正在尝试动态生成一个类。
  • @chepner 但对我来说,问题似乎是 OP 希望能够调用 Color.HEX() 来实例化一个实例,而不是 Color.HEX.value()。老实说,要做你想做的事,我只需要使用类定义语句和简单的del 名称,如果这让我感到困扰的话。当然,我只是认为这不是enum 的用例
  • 其实我忘了,因为class语句只是一个花哨的赋值语句,你可以直接将HexRgb的定义嵌套在Color中,这样就消除了需要typehackery。确实,它并没有消除必须使用value 来取回实际类型实例的问题。
  • 我运行了你的代码,不幸的是IDLE的子进程没有建立连接

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


【解决方案1】:

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

为了使Color.HEX('#00ff00')返回类Hex的实例,你需要定义Color.__call__。 (顺便说一句,请注意,您可以简单地在定义 Colorclass 语句中定义两个类,而不是在外部定义它们。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) 的任何内容。如果您认为您需要支持多重继承,这可能会改变,但考虑到 Enum 使用自定义元类,我将声明超出此问题范围的处理。

【讨论】:

  • 这很酷,但是为什么要把Enum 带入图片呢?只需使用Color(object) 并为其赋予类属性?
  • 这是一个关于Enum任何使用的问题。
  • Enum 有很多很好的用例——OP 不是其中之一。
  • 我不喜欢在里面嵌套类。因为它使它们在外面不可用。这样做我宁愿只在外部类定义中有枚举点。没有在里面定义它们。
  • 一开始你并没有在课堂外使用它们;问题的重点是如何写Color.HEX(...) 而不是Hex(...)
【解决方案2】:

我在您的问题中没有看到需要使用 Enum 或从中受益的任何内容。

Check this 了解使用 Enum 的指南。

Enum 确实提供了简单的会员测试,所以你可以这样做:

hex_value is rgb_value

hex_value in Color

使用aenum1 库,您的代码将如下所示:

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() 的详细信息,即存储的属性(redgreenbluehexrgb 等)。


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

【讨论】:

  • 我意识到我在这里使用枚举的方式不是很pythonic。我习惯了没有继承的语言。在枚举中对类型进行分组非常有用。但在这种情况下,除了路径之外,它没有提供任何好处。这可以通过使用普通继承将模块嵌套在文件夹中来实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多