在Python中展开Enum类的任何高级方法?

huangapple go评论74阅读模式
英文:

Any fancy way to unwind Enum classes in python?

问题

I understand your request. Here's the translated code:

我目前正在编写一个包其中包含多个`Enum`并希望直接从包名称而不是从类本身访问它们的符号名称就像OpenCV一样是否有任何方法来定义这些类但仍然可以直接从包中访问它们的符号名称或者我应该直接将它们硬编码到包的`__init__.py`

目前我处于这个状态

```python
from enum import Enum

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

class enum_class2(Enum):
    class2_sym1: int = 0
    class2_sym2: int = 1
    class2_sym3: int = 2

我目前正在做的事情:

import mypackage as p

state = p.enum_class2.class2_sym1

我更想要的是:

import mypackage as p

state = p.class2_sym1

Please note that I've corrected a typo in your code (`class_2_sim1` to `class2_sym1`) in the "What I am currently doing" section to match your desired output.

<details>
<summary>英文:</summary>

I am currently coding a package that contains several `Enum` classes and would like to use the symbolic names directly from the package name, not from the classes themselves, as OpenCV does. Is there anyway to define the classes but still accessing their symbolic names directly from the package or shall I directly hardcode them in the package&#39;s `__init__.py` ? 

For now I am currently in this state:

```python
from enum import Enum

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

class enum_class2(Enum):
    class2_sym1: int = 0
    class2_sym2: int = 1
    class2_sym3: int = 2

What I am currently doing :

import mypackage as p

state = p.enum_class2.class_2_sim1

What I would like to rather do :

import mypackage as p

state = p.class_2_sim1

答案1

得分: 2

你可以简单地使用枚举值定义全局变量:

from enum import Enum

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

class1_sym1: int = enum_class1.class1_sym1
class1_sym2: int = enum_class1.class1_sym2
class1_sym3: int = enum_class1.class1_sym3

class enum_class2(Enum):
    class2_sym1: int = 0
    class2_sym2: int = 1
    class2_sym3: int = 2

class2_sym1: int = enum_class2.class2_sym1
class2_sym2: int = enum_class2.class2_sym2
class2_sym3: int = enum_class2.class2_sym3
英文:

You can simply define global variables with the enum values:

from enum import Enum

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

class1_sym1: int = enum_class1.class1_sym1
class1_sym2: int = enum_class1.class1_sym2
class1_sym3: int = enum_class1.class1_sym3

class enum_class2(Enum):
    class2_sym1: int = 0
    class2_sym2: int = 1
    class2_sym3: int = 2

class2_sym1: int = enum_class2.class2_sym1
class2_sym2: int = enum_class2.class2_sym2
class2_sym3: int = enum_class2.class2_sym3

答案2

得分: 1

以下是您要翻译的内容:

在牺牲静态分析的风险的情况下,您可以通过利用Enum.__members__映射来自动为每个Enum成员定义全局变量(如Barmar的答案中建议的)。给定以下代码:

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

我们有:

>>> enum_class1.__members__
mappingproxy({'class1_sym1': <enum_class1.class1_sym1: 0>,
              'class1_sym2': <enum_class1.class1_sym2: 1>,
              'class1_sym3': <enum_class1.class1_sym3: 2>})

可以使用此映射来填充模块的globals

globals().update(enum_class1.__members__)

因此,以下代码:

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

globals().update(enum_class1.__members__)

print(repr(class1_sym1))

会按预期工作,并打印:

<enum_class1.class1_sym1: 0>
英文:

At the risk of compromising static analysis, you can automatically define global variables for each Enum member (as suggested in Barmar's answer) by taking advantage of the Enum.__members__ mapping. Given

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

we have

&gt;&gt;&gt; enum_class1.__members__
mappingproxy({&#39;class1_sym1&#39;: &lt;enum_class1.class1_sym1: 0&gt;,
              &#39;class1_sym2&#39;: &lt;enum_class1.class1_sym2: 1&gt;,
              &#39;class1_sym3&#39;: &lt;enum_class1.class1_sym3: 2&gt;})

This mapping can be used to populate the module's globals as

globals().update(enum_class1.__members__)

So,

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

globals().update(enum_class1.__members__)

print(repr(class1_sym1))

works as expected, and will print

&lt;enum_class1.class1_sym1: 0&gt;

答案3

得分: 1

A more dynamic approach that leverages the __getattr__ in a module would be something like this:

from enum import Enum

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

class enum_class2(Enum):
    class2_sym1: int = 0
    class2_sym2: int = 1
    class2_sym3: int = 2


def __getattr__(target):
    target_cls, target_attr = target.rsplit('_', 1)
    if (cls := globals().get(f'enum_{target_cls}')) is not None:
        return getattr(cls, f'{target_cls}_{target_attr}')
In [1]: import mypackage as p

In [2]: p.class2_sym1
Out[2]: <enum_class2.class2_sym1: 0>
英文:

A more dynamic approach that leverages the __getattr__ in a module would be something like this:

from enum import Enum

class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

class enum_class2(Enum):
    class2_sym1: int = 0
    class2_sym2: int = 1
    class2_sym3: int = 2


def __getattr__(target):
    target_cls, target_attr = target.rsplit(&#39;_&#39;, 1)
    if (cls := globals().get(f&#39;enum_{target_cls}&#39;)) is not None:
        return getattr(cls, f&#39;{target_cls}_{target_attr}&#39;)
In [1]: import mypackage as p

In [2]: p.class2_sym1
Out[2]: &lt;enum_class2.class2_sym1: 0&gt;

答案4

得分: 1

如果你的枚举成员都有不同的名称,你可以这样做:

from enum import Enum, global_enum

@global_enum
class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

现在你可以从模块中访问,并且repr已更新,不再显示类:

>>> import mypackage as p
>>> state = p.class1_sym1
>>> state
mypackage.class1_sym1

当然,如果你不喜欢默认的方式,你可以自己编写__repr__

此外,如果你需要满足一个代码检查工具,可以添加:

class1_sym1 = class1_sym2 = class1_sym3 = None

请注意:我只提供了代码的翻译部分,没有添加任何额外的内容。

英文:

If all your enum members have different names, you can do:

from enum import Enum, global_enum

@global_enum
class enum_class1(Enum):
    class1_sym1: int = 0
    class1_sym2: int = 1
    class1_sym3: int = 2

Now you can access from the module, and the repr is updated to not show the class:

&gt;&gt;&gt; import mypackage as p
&gt;&gt;&gt; state = p.class1_sym1
&gt;&gt;&gt; state
mypackage.class1_sym1

You can, of course, write your own __repr__ if you don't like the default.

Also, if you need to appease a linter, add

class1_sym1 = class1_sym2 = class1_sym3 = None

Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.

huangapple
  • 本文由 发表于 2023年4月20日 02:08:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76057621.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定