gpt4 book ai didi

python - Python 中的嵌套类枚举类

转载 作者:太空宇宙 更新时间:2023-11-04 01:55:33 25 4
gpt4 key购买 nike

我正在尝试在 Python 中创建一些具有属性的常量/类似枚举的对象/类。像这样。

from abc import ABC

class Entity(ABC):
# allow *labels as attributes

class Label(ABC):
@property
def spellings(self):
raise NotImplementedError

class PeriodLabel(Label):
@property
def months(self):
raise NotImplementedError

class MONTH(Entity):
class JANUARY(Label):
spellings = ['jan.', 'january']
class FEBRUARY(Label):
spellings = ['febr.', 'february']
.
.
.

class PERIOD(Entity):
class QUARTER(PeriodLabel):
spellings = ['q1', 'q2', 'q3', 'q4']
months = 3
class HALFYEAR(PeriodLabel):
spellings = ['6m']
months = 6
.
.
.

目标是从 MONTH 对象到 "MONTH" 作为 str。这部分很简单,因为我可以使用 MONTH.__name__。但我也想从 "MONTH"MONTH 采取相反的方式:

assert Entity("MONTH") == MONTH

我可以通过执行以下操作来实现这一点,但它似乎很老套,我需要比较快如闪电,所以我认为有更好的方法。

class Entity(ABC):

def __new__(cls, arg):
try:
print(cls.__name__)
candidate = eval(arg)
if issubclass(candidate, cls):
return candidate
except:
pass

我什至会接受 assert "MONTH"== MONTH 但我需要从字符串中获取类。我还需要从 "MONTH.JANUARY" 转到 MONTH.JANUARY。现在我尝试了很多不同的方法,但这个线程已经失控了。

编辑1

更简单的方法可能是

from typing import List, Optional


class Label:

def __init__(self, spellings: List[str]):
self.spellings = spellings


class Entity:

def __init__(self, **labels: Label):
for k, v in labels.items():
self.__setattr__(k, v)

def get(self, entity: str, label: Optional[str] = None):
raise NotImplementedError # todo: how?


PERIOD = Entity(Q1=Label(['q1', 'q2', 'q3', 'q4']))

assert Entity.get('PERIOD') == PERIOD
assert Entity.get('PERIOD', 'Q1') == PERIOD.Q1

缺点是它不是完全填充的,代码完成不会引用 PERIOD.Q1 因为 Q1 属性是通过 __setattr__ 间接创建的>

编辑2

这里有几个如何使用它的例子。性能很重要。虽然很难准确解释我想要什么。我希望它有点道理。

def some_function(entity_name, label_name, spellings)
print(f"{entity_name}-{label_name}:{spellings}"

# example 1
for entity in [MONTH, PERIOD, ...]:
entity_name = entity.__name__
for label in entity:
label_name = entity.__name__
some_function(entity_name, label_name, label.spellings)

# example 2 (given entity_name, label_name as strings)
entity = Entity.get(entity_name)
label = entity.get(label_name)
if entity == PERIODS:
if label.months == 3:
# do something

# example 3 (alternative to example 1)
for label in LABELS: # ALL_LABELS is auto collecting all labels
some_function(label.entity.__name__, label.__name__, label.spellings)

# example 4 (alternative to example 2)
label = LABELS.get(entity_name, label_name)
if label.entity == PERIODS:
if label.months == 3:
# do something

最佳答案

metaclasses来救援!

from __future__ import annotations
from typing import List, Dict, Tuple, Optional


class EntMeta(type):
_instances = {}

def __new__(mcs, classname: str, base_classes: Tuple[type], attrs: Dict) -> EntMeta:
qualname = attrs.get('__qualname__')
if qualname not in EntMeta._instances:
EntMeta._instances[qualname] = super().__new__(mcs, classname, base_classes, attrs)

return EntMeta._instances[qualname]

def __call__(cls, entity: str, label: Optional[str] = None) -> EntMeta:
if label is None:
qualname = entity
else:
qualname = '.'.join([entity, label])
try:
return cls._instances[qualname]
except KeyError:
raise ValueError(f"{qualname} is not a recognized entity")


class Entity(metaclass=EntMeta):
pass


class Label(metaclass=EntMeta):

@property
def spellings(self) -> List[str]:
raise NotImplementedError

class PeriodLabel(Label):

@property
def months(self) -> int:
raise NotImplementedError


class PERIOD(Entity):
class QUARTER(PeriodLabel):
spellings = ['q1', 'q2', 'q3', 'a4']
months = 3
class HALFYEAR(PeriodLabel):
spellings = ['q1', 'q2', 'q3', 'a4']
months = 6


class MONTH(Entity):
class JANUARY(Label):
spellings = ['jan.', 'january']


assert PERIOD == Entity('PERIOD')
assert MONTH == Entity('MONTH')
assert PERIOD.QUARTER == Entity('PERIOD', 'QUARTER')
assert PERIOD.HALFYEAR == Entity('PERIOD', 'HALFYEAR')
assert MONTH.JANUARY == Entity('MONTH', 'JANUARY')

关于python - Python 中的嵌套类枚举类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56908461/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com