我在使用Enum时遇到问题,其中一些属性具有相同的值。我认为Enums对python来说是新手,我找不到任何其他对此问题的引用。无论如何,假设我有以下
class CardNumber(Enum):
ACE = 11
TWO = 2
THREE = 3
FOUR = 4
FIVE = 5
SIX = 6
SEVEN = 7
EIGHT = 8
NINE = 9
TEN = 10
JACK = 10
QUEEN = 10
KING = 10
显然,这些是黑色插孔中的卡号及其对应值。十通王具有相同的价值。但如果我执行print(CardNumber.QUEEN)
之类的操作,我会回来<CardNumber.TEN: 10>
。更重要的是,如果我迭代这些,它只是迭代唯一值。
>>> for elem in CardNumber:
... print(elem)
CardNumber.ACE
CardNumber.TWO
CardNumber.THREE
CardNumber.FOUR
CardNumber.FIVE
CardNumber.SIX
CardNumber.SEVEN
CardNumber.EIGHT
CardNumber.NINE
CardNumber.TEN
如何解决这个问题?我希望CardNumber.QUEEN和CardNumber.TEN是唯一的,并且都出现在任何迭代中。我唯一能想到的就是给每个属性一个第二个值,它可以作为一个独特的id,但这似乎是unpythonic。
答案 0 :(得分:4)
更新
使用(aenum
)](https://pypi.python.org/pypi/aenum) 1 您有几个选择:
改为使用NamedConstant
:不提供任何Enum
个额外内容(迭代,查找等)[请参阅:以下原始答案]
使用NoAlias
:具有所有正常的Enum
行为,除了每个成员都是唯一的,并且按值查找不可用
NoAlias
的一个例子:
from aenum import Enum, NoAlias
class CardNumber(Enum):
_order_ = 'EIGHT NINE TEN JACK QUEEN KING ACE' # only needed for Python 2.x
_settings_ = NoAlias
EIGHT = 8
NINE = 9
TEN = 10
JACK = 10
QUEEN = 10
KING = 10
ACE = 11
并在使用中:
>>> list(CardNumber)
[<CardNumber.EIGHT: 8>, <CardNumber.NINE: 9>, <CardNumber.TEN: 10>, <CardNumber.JACK: 10>, <CardNumber.QUEEN: 10>, <CardNumber.KING: 10>, <CardNumber.ACE: 11>]
>>> CardNumber.QUEEN == CardNumber.KING
False
>>> CardNumber.QUEEN is CardNumber.KING
False
>>> CardNumber.QUEEN.value == CardNumber.KING.value
True
>>> CardNumber(8)
Traceback (most recent call last):
...
TypeError: NoAlias enumerations cannot be looked up by value
原始答案
如果您想要命名常量而不关心Enum
的其他功能,可以使用aenum library中的NamedConstant
类:
from aenum import NamedConstant
class CardNumber(NamedConstant):
ACE = 11
TWO = 2
THREE = 3
FOUR = 4
FIVE = 5
SIX = 6
SEVEN = 7
EIGHT = 8
NINE = 9
TEN = 10
JACK = 10
QUEEN = 10
KING = 10
重复值仍然不同:
>>> CardNumber.TEN is CardNumber.JACK
False
>>> CardNumber.TEN == CardNumber.JACK
True
>>> CardNumber.TEN == 10
True
1 披露:我是Python stdlib Enum
,enum34
backport和Advanced Enumeration (aenum
)图书馆的作者。
答案 1 :(得分:2)
是的,具有重复值的标签将变为第一个此类标签的别名。
您可以枚举7474774 (<= value of user_id),ODFLKGJDFLKGJ(<= value of product)
属性,它是一个包含别名的有序字典:
__members__
但是,如果必须具有唯一的标签和值对(而不是别名),那么>>> for name, value in CardNumber.__members__.items():
... print(name, value)
...
ACE CardNumber.ACE
TWO CardNumber.TWO
THREE CardNumber.THREE
FOUR CardNumber.FOUR
FIVE CardNumber.FIVE
SIX CardNumber.SIX
SEVEN CardNumber.SEVEN
EIGHT CardNumber.EIGHT
NINE CardNumber.NINE
TEN CardNumber.TEN
JACK CardNumber.TEN
QUEEN CardNumber.TEN
KING CardNumber.TEN
是错误的方法;它与纸牌游戏的用例不匹配。
在这种情况下,最好使用字典(如果订单也很重要,请考虑使用enum.Enum
。)
答案 2 :(得分:0)
感谢这里的答案,但对于使用enum.auto()
的人,这里是具有别名或重复的枚举值的扩展答案
import enum
PREDICT_ALIAS = enum.auto()
class Mode(enum.Enum):
FIT = enum.auto()
EVALUATE = enum.auto()
PREDICT = PREDICT_ALIAS
INFER = PREDICT_ALIAS # alias mode
print(Mode.PREDICT is Mode.INFER) # return True :)
答案 3 :(得分:0)
对于那些仍不考虑使用aenum
或OrderedDict
的人,仍然可以四处逛逛:
import enum
class AliasedEnum(enum.Enum):
def __init_subclass__(cls, *kargs, **kwargs):
import inspect
# unfortunately, there's no cleaner ways to retrieve original members
for stack in reversed(inspect.stack()):
frame_locals = stack[0].f_locals
enum_members = frame_locals.get('enum_members')
if enum_members is None:
try:
enum_members = frame_locals['classdict']._member_names
except (KeyError, AttributeError):
continue
break
else:
raise RuntimeError('Unable to checkout AliasedEnum members!')
# patch subclass __getattribute__ to evade deduplication checks
cls._shield_members = list(enum_members)
cls._shield_getattr = cls.__getattribute__
def patch(self, key):
if key.startswith('_shield_'):
return object.__getattribute__(self, key)
if key.startswith('_value'):
if not hasattr(self, '_name_'):
self._shield_counter = 0
elif self._shield_counter < self._shield_members.index(self._name_):
self._shield_counter += 1
class unequal:
pass
return unequal
return self._shield_getattr(key)
cls.__getattribute__ = patch
class Fck(AliasedEnum):
A = 0
B = 0
C = 0
这依赖于以下事实:标准enum.EnumMeta.__new__
使用O(n²)
算法进行重复数据删除以处理不可散列的值,因此应将其视为不良做法。它仍然可以达到预期的效果:
$ python -i aliased_enum.py
>>> Fck.A
<Fck.A: 0>
>>> Fck.B
<Fck.B: 0>
>>> Fck.C
<Fck.C: 0>
已通过Python3.7.4
测试,并且可以在cpython
标准库中移植。
答案 4 :(得分:0)
一种简单的方法是将值放在对象内:
C:\Users\Devesh\ShoppingList>react-native run-android
info Running jetifier to migrate libraries to AndroidX. You can disable it using "--no-jetifier" flag.
Jetifier found 967 file(s) to forward-jetify. Using 4 workers...
info Starting JS server...
info Installing the app...
FAILURE: Build failed with an exception.
* What went wrong:
Could not initialize class org.codehaus.groovy.runtime.InvokerHelper
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 864ms
error Failed to install the app. Make sure you have the Android development environment set up: https://reactnative.dev/docs/environment-setup. Run CLI with --verbose flag for more details.
Error: Command failed: gradlew.bat app:installDebug -PreactNativeDevServerPort=8081
FAILURE: Build failed with an exception.
* What went wrong:
Could not initialize class org.codehaus.groovy.runtime.InvokerHelper
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 864ms
at makeError (C:\Users\Devesh\ShoppingList\node_modules\execa\index.js:174:9)
at C:\Users\Devesh\ShoppingList\node_modules\execa\index.js:278:16
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async runOnAllDevices (C:\Users\Devesh\ShoppingList\node_modules\@react-native-community\cli-platform-android\build\commands\runAndroid\runOnAllDevices.js:94:5)
at async Command.handleAction (C:\Users\Devesh\ShoppingList\node_modules\react-native\node_modules\@react-native-community\cli\build\index.js:186:9)
顺便说一句,不要对Value类使用@dataclass装饰器。数据类比较其属性的值以检查对象是否相等,这意味着它的行为与默认的Enum完全一样!