Python 3.11的更强大的枚举
#编程 #python #todayilearned

Python 3.11在去年末发布。通常,有beaucoup de nouveautés。一个部分比其他部分更吸引了我的Å:有beaucoup de changements et d'ajouts sur les enums!好的,速度是我正在寻找如何做的事情,我看到了Python 3.11精确带来了此功能...更新了我的解释器以测试â!

在本文中,我向您介绍了最有前途的消息。

3.11:enum模块的重要版本

koude0模块出现在version 3.4PEP 435的含义以来非常稳定。

出于文档的目的,我们看到:

版本3.6中的新事物:FlagIntFlagauto

版本3.11:StrEnumEnumCheckReprEnumFlagBoundaryFlagBoundarypropertymembernonmembernonmemberglobal_enumshow_flag_values

版本3.11是一个带来许多新版本的版本。列出了9个以文档目的列出的,但是下面有10áµ:verify()。在现实生活中,la documentation est loin d'être parfaite,但我们这样做。

愤怒的街道

为了娱乐,我致力于在愤怒的街道上使用基本示例。什么 ?!你不知道愤怒的街道吗?但是很快就匆匆忙忙的agrandir您的流行文化!

我的祭司显然是2,但我也会有点使用1

在Python 3.11之前可以做什么

如果您想列出Rage 2的街道级别,则可以从Python 3.4:
中制作这样的数字

class Stages(Enum):
    DOWNTOWN = 1
    BRIDGE_CONSTRUCTION = 2
    AMUSEMENT_PARK = 3
    STADIUM = 4
    # ... et plusieurs autres encore !

他们非常宽容,例如,我们可以做类似的事情:

class Stages(Enum):
    DOWNTOWN = 1
    BRIDGE_CONSTRUCTION = 2
    AMUSEMENT_PARK = 'three'
    STADIUM = [4]

因此,可以具有不同类型的值。 â在某些情况下可以实用,但是我们想制作值类型,如我们的示例中,每个级别对应一个数字。正是由于这个原因,IntEnum已引入Python 3.6:

class Stages(IntEnum):
    DOWNTOWN = 1
    BRIDGE_CONSTRUCTION = 2
    AMUSEMENT_PARK = 3
    STADIUM = 'four'

我们在ex -cation中获得一个例外:ValueError: invalid literal for int() with base 10: 'four'

请注意,如果我们有STADIUM = '4'(请注意4个简单引号在4左右),则代码可行。实际上,正如例外表明的那样,IntEnum使用int()获取该值,事实证明该int('4') == 4。因此,我们可以用作 initializer 一个提供def __int__(self) -> int螨的类的实例。

IntEnum实际上是“ 混合枚举”。 混合枚举的原理是使所需类型和enum的(多个)外壳。这对我的鹅来说不是很好的纪录片,但是在"Enum HOWTO"中有解释(ici和一些)。因此,我们获得了一个数字,其值一定是相同类型的T

在这些提醒之后,我们将介绍以下版本3.11的更改。

ReprEnum

如果我们听到ReprEnum而不是Enum,我们相信一个老年人的转换为 string 的价值类型。 documentation占上风:

ReprEnum使用Enumrepr(),但是混合数据类型的str()

(...)

ReprEnum继承来保留混合数据类型的str() / format(),而不是使用Enum-default str()。< / p>

IntEnums的显示改变了ReprEnum的原因

What’s New In Python 3.11告诉我们:

IntEnum(...)更改为现在继承的逆逆因,因此他们的str()输出现在与format()匹配(str(AnIntEnum.ONE)format(AnIntEnum.ONE) return '1',而在str(AnIntEnum.ONE)返回'AnIntEnum.ONE'

让我们看一下它给我们的Stages(IntEnum)的数量:

print('member\t', Stages.DOWNTOWN)
print('name\t', Stages.DOWNTOWN.name)
print('value\t', Stages.DOWNTOWN.value)
print('str()\t', str(Stages.DOWNTOWN))
print('repr()\t', repr(Stages.DOWNTOWN))
print('f-str\t', f'{Stages.DOWNTOWN}')

A 3.10:

member   Stages.DOWNTOWN
name     DOWNTOWN
value    1
str()    Stages.DOWNTOWN
repr()   <Stages.DOWNTOWN: 1>
f-str    1

3.11中的修改显示:

member   1
name     DOWNTOWN
value    1
str()    1
repr()   <Stages.DOWNTOWN: 1>
f-str    1

就个人而言,我发现它更合乎逻辑,但是此更改可能会对现有代码产生后果!

StrEnum,像IntEnum一样,但是用丁字裤

我们通常需要制作一个仅包含 thongs 的数字,例如列出游戏中的字符:

class Characters(StrEnum):
    AXEL = 'Axel Stone'
    BLAZE = 'Blaze Fielding'
    MAX = 'Max Thunder'
    SKATE = 'Eddie "Skate" Hunter'

StrEnum he ReprEnum,这意味着print(str(Characters.BLAZE))print(f'{Characters.BLAZE}')显示Blaze Fielding。如果我们完成了Characters(Enum),则显示会给Characters.BLAZE。至于IntEnum,我找到了这个逻辑显示。

我们可以将auto()StrEnum

class Characters(StrEnum):
    # ...
    SKATE = auto()

str(Characters.SKATE))将是skate

有可能在Python 3.11之前制作一个StrEnum,并具有简单的枚举,但打字不太强。例如,我们可以做:

class Characters(str, Enum):
    AXEL = 'Axel Stone'
    BLAZE = 'Blaze Fielding'
    MAX = 'Max Thunder'
    SKATE = 8

那是残酷的。确实,可以使用str(8)从8开始构建A thong 。它没有在文档中说,但是我们可以看一下StrEnumenum.py中的含义,并且我们看到制造商被降低并明确地与isinstance(..., str)进行了静脉。 IntEnum并非如此。

@verify更有可能

@unique自从检测到enum模块以来就已经被阻止了,并可以确保每个成员都有一个……唯一! ð

完成游戏的水平并确保它们都有不同的数字是非常好的。示例:

@unique
class Stages(IntEnum):
    DOWNTOWN = 1
    BRIDGE_CONSTRUCTION = 2
    AMUSEMENT_PARK = 3
    STADIUM = 3

此代码是一个例外:ValueError: duplicate values found in <enum 'Stages'>: STADIUM -> AMUSEMENT_PARK

一个新的宣布,koude69,出现在3.11中:

专门用于枚举的class装饰师。 EnumCheck的成员用于指定应在装饰的枚举上检查哪些约束。

因此,他会吸收koude6s的参数:

Enumcheck 包含verify()装饰器使用的选项,以确保各种约束;失败的约束导致ValueError

目前可以使用koude79koude80koude81@verify(UNIQUE)是哪个

我们可以在参数上花几个标志,这非常适合我们的示例:

@verify(UNIQUE, CONTINUOUS)
class Stages(IntEnum):
    DOWNTOWN = 1
    BRIDGE_CONSTRUCTION = 2
    AMUSEMENT_PARK = 3
    STADIUM = 5

有一个例外,我们缺少一个值:ValueError: invalid enum 'Stages': missing values 4

使成员可以在整个名称空间中访问

要访问会员,您通常必须通过类:Stages.STADIUM

访问它。

在某些情况下(以及随之而来的名称冲突的通风风险),您可能需要直接使用STADIUM。从Python 3.11可以使用@global_enum注释您的课程。

控制什么是会员,什么不是成员

两个nouveaux décorateurs允许我们明确控制数字中的成员,什么不是:

@enum.member
用于枚举的装饰器:其目标将成为成员。

@enum.nonmember
用于枚举的装饰器:其目标不会成为会员。

当我们谈论一个数字成员时,我们正在谈论他的不同价值观。

这个@member鹿器非常实用,可以最终得到许多值的数字。

对于Rage 2的街道,我们需要角色可以做的3个基本动作中的许多。功能是实现动作的好人。顺便说一句,在Enum的de -rightere类中完成的函数是 static方法。因此,以下代码无法完成我们想要的事情,因为它会在没有价值的情况下创造无尽的性:

class Controls(Enum):
    def special_move():
        print('Special move, massive damage!')

    def attack():
        print('Attack? OK! Punch!')

    def jump():
        print('The floor is lava! Jump!')

print(list(Controls))
Controls.attack()

此海报代码:

[]
Attack? OK! Punch!

要纠正这一点,只需注释函数:

class Controls(Enum):
    @member
    def special_move():
        print('Special move, massive damage!')

    @member
    def attack():
        print('Attack? OK! Punch!')

    @member
    def jump():
        print('The floor is lava! Jump!')


print(list(Controls))
Controls.attack.value()

我们这次得到了:

[<Controls.special_move: <function Controls.special_move at 0x0000015B0080AD40>>,
        <Controls.attack: <function Controls.attack at 0x0000015B00778680>>,
        <Controls.jump: <function Controls.jump at 0x0000015B00822200>>]
Attack? OK! Punch!

完美!请注意,Controls.attack不是 calblable (因为它是数字的成员),并且必须将.value用于访问该功能。

相反,如果您希望给定的一个在班上静态,则必须使用@nonmember()。语法有点令人惊讶(我发现),官方文档没有举例说明。这是道路的小孩子:

class Characters(StrEnum):
    playable = nonmember(True)
    AXEL = 'Axel Stone'
    BLAZE = 'Blaze Fielding'
    MAX = 'Max Thunder'
    SKATE = 'Eddie "Skate" Hunter'


print(Characters.playable)

与往常一样,在Python中,可以通过其成员访问类字段,因此您可以使用Characters.SKATE.playable

结论

此版本的Python 3.11有很多新的条目!当您的主要语言是C ++时,enumérations确实非常基本,您就像一个孩子在糖果店里!我很遗憾,即使是文档不贴上的(某些功能也很糟糕,甚至没有纪录片),而且太奇怪的是(例如show_flag_values(),它不会添加到__all__中,并且其使用真的很差)。我们敢打赌,它将在下一个版本中链接,并在enum中利用此补充功率!

package