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

我很清楚,如果您有一个使用枚举的类名进行类型提示的类方法,那么可以通过破解来使其在Python 3.6及以下版本中正常工作。

而不是...

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

您需要像这样使用字符串值...

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

我相信在python 3.7和更高版本中,您无需使用引号就可以解决这种“ hack”问题,这是一种Python方式。原因是“在所有方法和变量都先完成之前,该类还不存在”。由于该类尚不存在,所以我还不能使用该类的名称,而必须使用带引号的字符串作为技巧。

但是,我正在尝试更进一步,并使用默认值。那是行不通的。

在python 3.7及更高版本中,是否有针对python的pythonic方法不是黑客??

代码

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的元组而不是实际值。

woaixu13142 回答:具有默认Enum值的Enum类方法失败

虽然这绝对是一种解决方法,但对我来说似乎很好:

@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
,

Release Enum中可以做一些事情来使生活更轻松,首先是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成员:

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

,或者,如果默认值可以是任何成员,则类似于this answer的东西应该起作用:

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是以前的所有成员,并使用装饰器方法):

@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异常。

,

从@ufoxDan那里得到了一个提示,但他试图使其变通方法更少,更自然。

基本上,我从type(release)之前检查return开始,发现我得到了结果。

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

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

Canary

这似乎是获得结果的最有效的方法。这似乎也是阅读代码且不重复代码的最佳方法。任何人都应该能够实现看起来相似的东西。

本文链接:https://www.f2er.com/3146861.html

大家都在问