我打算在代码中使用非常规的Enum
,但是遇到一个问题,当Enum
使用不正确时,我需要我的属性来引发错误,但是,它没有抛出异常,而是输出了我财产的地址。
我希望我的代码如何工作:
Enum.MEMBER.text
时,返回Enum.MEMBER
替代文本。Enum.text
时,抛出错误。这是代码段
class MyEnum(Enum):
@property
def text(self):
if isinstance(self._value_,MyCapsule): return self._value_.text
raise Exception('You are not using an Enum!')
return None
@property
def value(self):
if isinstance(self._value_,MyCapsule): return self._value_.value
raise Exception('You are not using an Enum!')
return None
class MyCapsule:
def __init__(self,value,text,more_data):
self._value_, self._text_ = (value,text)
@property
def text(self): return self._text_
@property
def value(self): return self._value_
class CustomData(MyEnum):
ONE = MyCapsule(1,'One','Lorem')
TWO = MyCapsule(2,'Two','Ipsum')
TRI = MyCapsule(3,'Tri','Loipsum')
A = CustomData.ONE
B = CustomData
print(A.text, A.value,sep=' | ')
print(B.text, B.value,sep=' | ')
输出为:
One | 1
<property object at 0x0000016CA56DF0E8> | <property object at 0x0000016CA56DF278>
我期望的是
One | 1
Unexpected exception at ....
是否有解决此问题的方法,或者我不应该以此方式写Enum
?
答案 0 :(得分:1)
自定义描述符可以解决问题:
class property_only(object):
#
def __init__(self, func):
self.func = func
#
def __get__(self, instance, cls):
if instance is None:
raise Exception('You are not using an Enum!')
else:
return self.func(instance)
#
def __set__(self, instance, value):
# raise error or set value here
pass
然后更改您的基本枚举以使用它:
class MyEnum(Enum):
@property_only
def text(self):
return self._value_.text
@property_only
def value(self):
return self._value_.value
class MyCapsule:
def __init__(self, value, text, more_data):
self._value_, self._text_ = (value, text)
class CustomData(MyEnum):
ONE = MyCapsule(1, 'One', 'Lorem')
TWO = MyCapsule(2, 'Two', 'Ipsum')
TRI = MyCapsule(3, 'Tri', 'Loipsum')
并在使用中:
>>> CustomData.text
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __get__
Exception: You are not using an Enum!
虽然解决了“只能从枚举中访问”的问题,但是当您要访问text
和value
时,仍然有很多间接方式:
>>> CustomData.ONE.value._value_
1
>>> CustomData.ONE.value._text_
'One'
解决方案是将MyCapsule
直接合并到CustomData
中:
from enum import Enum
class property_only(object):
#
def __init__(self, func):
self.func = func
#
def __get__(self, instance, cls):
if instance is None:
raise Exception('You are not using an Enum!')
else:
return self.func(instance)
#
def __set__(self, instance, value):
# raise error or set value here
pass
class CustomData(Enum):
#
ONE = 1, 'One', 'Lorem'
TWO = 2, 'Two', 'Ipsum'
TRI = 3, 'Tri', 'Loipsum'
#
def __new__(cls, value, text, more_data):
member = object.__new__(cls)
member._value_ = value
member._text_ = text
# ignoring more_data for now...
return member
#
@property_only
def text(self):
return self._text_
#
@property_only
def value(self):
return self._value_
并在使用中:
>>> CustomData.ONE
<CustomData.ONE: 1>
>>> CustomData.ONE.value
1
>>> CustomData.ONE.text
'One'
>>> CustomData.ONE.name
'ONE'
>>> CustomData.text
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __get__
Exception: You are not using an Enum!
>>> CustomData.value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __get__
Exception: You are not using an Enum!
披露:我是Python stdlib Enum
,enum34
backport和Advanced Enumeration (aenum
)库的作者。