具有默认Enum值的Enum Class方法失败



我很清楚,如果你有一个使用枚举类名进行类型提示的类方法,那么有一个破解方法可以让它适用于Python 3.6及以下版本。

而不是。。。

class Release(Enum):
...
@classmethod
def get(cls, release: Release):
...

你需要像这样使用字符串值…

class Release(Enum):
...
@classmethod
def get(cls, release: "Release"):
...

我相信在Python3.7及以上版本中,有一种蟒蛇式的方法可以绕过这种"破解",你不必使用引号。原因是"在所有方法和变量都先完成之前,类还不存在"。由于这个类还不存在,我还不能使用类名,必须使用带引号的字符串作为破解方法。

但是,我尝试更进一步,使用默认值。这是行不通的。Python 3.6有没有一种Python方法不是破解此外,python 3.7及以上版本是否有修复程序?

代码

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())

使用此代码,我得到以下错误消息

AttributeError: 'tuple' object has no attribute 'current'

这是因为它返回的是Canary元组,而不是实际值。

虽然这绝对是一个变通方法,但这似乎对我很有效:

@classmethod
def get_all_releases(cls, release: "Release" = Canary):  # Default Value = Release.Canary
if release == (Release.Canary.value,):
return Release.Canary.current
return release.current

它适用于您指定给Canary的任何值。所以,只要这是你的默认,我相信它会起作用。


为了更通用,您只需要调整类定义中的默认值,而不是每个函数,您可以按如下方式进行:

class Release(Enum):
Canary = 6,
Beta = 2,
RC = 3,
Stable = 4
default = Canary
...
@classmethod
def get_all_releases(cls, release: "Release" = default):
if release == (Release.Canary.value,):
return Release.Canary.current
return release.current

他的回答得到了@ufoxDan的提示,但试图让它不那么简单,更自然。

基本上,我在returning之前先检查type(release),然后注意到我得到了…的结果。。

<enum 'Release'>
<enum 'Release'>
<enum 'Release'>
<enum 'Release'>
<class 'tuple'>

我注意到,如果类型是Release,那么我就可以执行代码,但是如果它是其他任何东西,比如None而不是未创建的Canary类型,那么我可以假设它要求Canary。所以我做了以下。。。

@classmethod
def get_all_releases(cls, release: "Release" = None):
if type(release) is Release:
return release.current
return Release.Canary.current
# Now these all work
print(Release.get_all_releases())
print(Release.get_all_releases(Release.Canary))
print(Release.get_all_releases(Release.Stable))

这似乎是实现结果的最愚蠢的方式。这似乎也是阅读代码和不重复代码的最佳方式。任何人都应该能够实现类似的东西。

ReleaseEnum中可以做几件事来让生活更轻松,第一件事是这里显示的技术:

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成员:

@classmethod
def get_all_releases(cls):
return list(cls[0]).current

或者,如果默认成员可以是任何成员,那么类似于这个答案的东西应该起作用:

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是以前的所有成员,并使用decorator方法(:

@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']

原始答案

你的代码有问题在这里:

class Release(Enum):
Canary = 1,

通过包含这个额外的逗号,您已经将Canary的值设置为(1, )。删除该逗号以消除tuple异常。

最新更新