具有默认Enum值的Enum类方法失败 [英] Enum Class method with default Enum value fails
问题描述
我很清楚,如果您有一个使用枚举的类名进行类型提示的类方法,则可以通过破解来使其在Python 3.6及以下版本中正常工作。
I am well aware that if you have a class method that uses the enum's class name for type hinting, there is a hack to get it to work for Python 3.6 and below.
而不是...
class Release(Enum):
...
@classmethod
def get(cls, release: Release):
...
您需要像这样使用字符串值...
You need to use the string value like so...
class Release(Enum):
...
@classmethod
def get(cls, release: "Release"):
...
我相信在Python 3.7及更高版本中,围绕这种 hack存在一种Python方式,您无需使用引号。原因是直到所有方法和变量都先完成后该类才存在。由于该类尚不存在,因此我无法使用该类的名称,而必须使用带引号的字符串作为技巧。
I believe in Python 3.7 and above there is a pythonic way around this "hack" where you don't have to use quotes. The reason is something along the lines of "the class doesn't exist yet until all the methods and varibles are done first". Since the class doesn't exist yet, I can't use the class name yet, and have to use the quoted string as a hack.
但是,我正在尝试更进一步,并使用默认值。那是行不通的。 另外,Python 3.7及更高版本中是否有修复程序?
However, I am trying to go one step further and use a default value. And that doesn't work. Is there a pythonic approach for Python 3.6 that isn't a hack? Also, is there a fix in python 3.7 and above?
from enum import Enum
class Release(Enum):
Canary = (1, [])
Beta = (2, [1])
RC = (3, [2, 1])
Stable = (4, [3, 2, 1])
def __new__(cls, value, cascade):
obj = object.__new__(cls)
obj._value_ = value
obj.current = ["Release" * value] # This would technically be a list of all releasese in this enum. This is just to emulate different values
obj.cascade = cascade
return obj
@classmethod
def get_all_releases(cls, release: "Release" = Canary): # Default Value = Release.Canary
return release.current
print(Release.get_all_releases(Release.Canary))
print(Release.get_all_releases(Release.Beta))
print(Release.get_all_releases(Release.RC))
print(Release.get_all_releases(Release.Stable))
# Error. Even with default value
# print(Release.get_all_releases())
使用此代码我收到以下错误消息
With this code I get the following error message
AttributeError: 'tuple' object has no attribute 'current'
这是因为它返回Canary的元组而不是实际值。
That is because it returns the tuple of Canary instead of the actual value.
推荐答案
您可以在发行版
枚举
中进行以下操作生活更轻松,第一种是在此处所示的技术:
There are a couple things you can do in your Release
Enum
to make life easier, the first being a technique shown here:
def __new__(cls, value, cascade):
obj = object.__new__(cls)
obj._value_ = value
obj.current = ["Release" * value] # not sure what this should actually be
# if always the previous versions (don't need cascade defined)
obj.cascade = sorted(list(cls), reverse=True)
# if some already defined subset (need cascade defined)
obj.cascade = [cls._value2member_map_(c) for c in cascade]
return obj
第二种方法可以有两种方式-您的默认值始终是第一个 Enum
成员:
The second technique can go two ways -- your default is always the first Enum
member:
@classmethod
def get_all_releases(cls):
return list(cls[0]).current
或者,如果默认值可以是任何成员,则类似于此答案应有效:
or, if the default could be any member, then something similar to this answer should work:
class add_default:
"""
add DEFAULT psuedo-member to enumeration; use first member if none specified
(default should be name of member)
"""
def __init__(self, default=''):
self._default = default
def __call__(self, enumeration):
if self._default:
member = enumeration[self._default]
else:
member = enumeration[enumeration._member_names_[0]]
enumeration._member_map_['DEFAULT'] = member
return enumeration
您的最终 Enum
会看起来像(假设 cascade
是以前的所有成员,并使用装饰器方法):
Your final Enum
would then look like (assuming cascade
is all previous members and using the decorator approach):
@add_default('Canary')
class Release(Enum):
Canary = 1
Beta = 2
RC = 3
Stable = 4
def __new__(cls, value):
obj = object.__new__(cls)
obj._value_ = value
obj.current = ["Release" * value] # not sure what this should actually be or how it's calculated
obj.cascade = list(cls)[::-1]
return obj
@classmethod
def get_all_releases(cls, release: "Release" = None):
if release is None:
release = cls.DEFAULT
return release.current
并在使用中:
>>> Release.DEFAULT
<Release.Canary: 1>
>>> Release.get_all_releases()
['Release']
>>> Release.get_all_releases(Release.RC)
['ReleaseReleaseRelease']
原始答案
您的代码存在的问题在这里:
The problem you are having with your code is here:
class Release(Enum):
Canary = 1,
通过添加多余的逗号,您使 Canary
的值变为(1,)
。删除该逗号以消除 tuple
异常。
By including that extra comma you have made the value for Canary
be (1, )
. Remove that comma to get rid of the tuple
exception.
这篇关于具有默认Enum值的Enum类方法失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!