我正在尝试用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
。现在我已经尝试了很多不同的方法,但是这个思路已经失控了。你知道吗
更简单的方法是
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__
间接创建的
下面是几个如何使用它的例子。表现很重要。但要准确地解释我想要什么真的很难。我希望这有点道理。你知道吗
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
^{} 去救援!你知道吗
可以使用实例here所示的属性定义枚举。如果内置枚举可以满足我的需要,我会避免定义自己的元类-下面是一个非常粗糙的Poc:
相关问题 更多 >
编程相关推荐