资讯专栏INFORMATION COLUMN

python模块之enum_上

kelvinlee / 1058人阅读

摘要:模块定义了种枚举类装饰器助手在中加入创建枚举注意点枚举值可以是任何类型,如果值不重要可以使用自动选择。使用装饰器可以对枚举值进行唯一约束枚举专用的类装饰器。序列化一般要求序列化的枚举要定义在模块顶层,因为反序列化要求枚举能够从模块导入。

enum模块定义了:

4种枚举类:Enum, IntEnum, Flag, IntFlag

装饰器:unique()

助手:auto

Flag, IntFlag, auto在python3.6中加入

创建枚举
from enum import Enum
class Color(Enum):
    RED = 2
    GREEN = 4
    BLUE = 6

注意点:
1. 枚举值可以是任何类型,如果值不重要可以使用auto()自动选择。但在有其他已定义的值的情况下,谨慎与auto混用
2. Color是枚举类,Color.RED等是枚举成员,枚举成员拥有name和value属性
3. 虽然使用class关键字创建,但枚举并不是常规意义上的python类

枚举成员的展现形式:

>>>print(Color.RED)
Color.RED

>>>print(repr(Color.RED))

枚举成员的type类型是其所属的枚举类:

>>>type(Color.RED)

>>>isinstance(Color.RED, Color)
True

枚举支持按照定义时的顺序进行迭代:

>>>for color in Color:
...    print(color)
...
Color.RED
Color.GREEN
Color.BLUE    

枚举成员是可哈希的,因此可以在字典和集合中使用:

>>> apples = {}
>>> apples[Color.RED] = "red delicious"
>>> apples[Color.GREEN] = "granny smith"
>>> apples == {Color.RED: "red delicious", Color.GREEN: "granny smith"}
True
对枚举成员及其属性的程序化访问

通过值访问枚举成员:

>>>Color(2)

通过名称访问枚举成员:

>>>Color["RED"]

获取枚举成员的名称和值:

>>>member = Color.RED
>>>member.name
"RED"
>>>member.value
2
枚举成员及其值的重复性问题

拥有两个相同名称的枚举成员是不允许的:

>>> class Shape(Enum):
...     SQUARE = 2
...     SQUARE = 3
...
Traceback (most recent call last):
...
TypeError: Attempted to reuse key: "SQUARE"

不过不同的枚举成员允许拥有相同的值。后定义的成员是先定义的成员的别名,通过值或名称访问时都将返回先定义的成员:

>>> class Shape(Enum):
...     SQUARE = 2
...     DIAMOND = 1
...     CIRCLE = 3
...     ALIAS_FOR_SQUARE = 2
...
>>> Shape.SQUARE

>>> Shape.ALIAS_FOR_SQUARE

>>> Shape(2)

注意点:任意两个枚举属性(包括成员、方法等)不允许存在相同的名称

枚举值唯一约束

默认情况下,允许多个成员拥有相同的值。使用unique装饰器可以对枚举值进行唯一约束

@enum.unique: 枚举专用的类装饰器。它在枚举的__members__属性中只要查找到成员别名就抛出ValueError异常

>>> from enum import Enum, unique
>>> @unique
... class Mistake(Enum):
...     ONE = 1
...     TWO = 2
...     THREE = 3
...     FOUR = 3
...
Traceback (most recent call last):
...
ValueError: duplicate values found in : FOUR -> THREE
自动生成枚举值

对于不重要的枚举值,可以使用auto自动生成:

>>> from enum import Enum, auto
>>> class Color(Enum):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> list(Color)
[, , ]

auto生成什么值取决于_generate_next_value_()方法,可重写:

>>> class AutoName(Enum):
...     def _generate_next_value_(name, start, count, last_values):
...         return name
...
>>> class Ordinal(AutoName):
...     NORTH = auto()
...     SOUTH = auto()
...     EAST = auto()
...     WEST = auto()
...
>>> list(Ordinal)
[, , , ]
迭代

对枚举成员的迭代,并不会包含成员别名:

>>> list(Shape)
[, , ]

__members__属性是一个映射了枚举成员及其名称的有序字典,包括成员别名:

>>> for name, member in Shape.__members__.items():
...     name, member
...
("SQUARE", )
("DIAMOND", )
("CIRCLE", )
("ALIAS_FOR_SQUARE", )

>>> [name for name, member in Shape.__members__.items() if member.name != name]
["ALIAS_FOR_SQUARE"]
枚举比较(后两种不适用于IntEnum)
>>> Color.RED is Color.RED
True

>>> Color.RED == Color.BLUE
False

>>> Color.RED < Color.BLUE
Traceback (most recent call last):
  File "", line 1, in 
TypeError: "<" not supported between instances of "Color" and "Color"

>>> Color.BLUE == 6 # 与非枚举的值进行等值比较总是返回False
False
允许的枚举成员与属性

枚举是python类,也可以拥有普通方法和特殊方法:

class Mood(Enum):
    FUNKY = 1
    HAPPY = 3

    def describe(self):
        # self is the member here
        return self.name, self.value

    def __str__(self):
        return "my custom str! {0}".format(self.value)

    @classmethod
    def favorite_mood(cls):
        # cls here is the enumeration
        return cls.HAPPY

注意点:如果枚举中定义了__new()__或者__init__()方法,赋值给枚举成员的值将被传递到__new()__或者__init__()

枚举的继承限制

自定义枚举类必须继承自一个枚举基类,至多一个具体的数据类型以及0至多个混合类。继承顺序如下:

class EnumName([mix-in, ...,] [data-type,] base-enum):
    pass

基类枚举如果已经定义了成员,则不能被任何子类继承,如下第一种是不允许的,但第二种可以:

>>> class MoreColor(Color):
...     PINK = 17
...
Traceback (most recent call last):
...
TypeError: Cannot extend enumerations
>>> class Foo(Enum):
...     def some_behavior(self):
...         pass
...
>>> class Bar(Foo):
...     HAPPY = 1
...     SAD = 2
...

不能这么做的原因是可能破坏某些重要的不允许改变的值(原话是would lead to a violation of some important invariants of bytes and instances)。

序列化
>>> from a.b import Color
>>> from pickle import dumps, loads
>>> Color.RED is loads(dumps(Color.RED))
True

一般要求序列化的枚举要定义在模块顶层,因为反序列化要求枚举能够从模块导入。不过在第4版的pickle协议中,已经可以序列化嵌套在类中的枚举

通过在枚举中定义__reduce_ex__()方法,可以修改枚举成员的序列化/反序列化行为

Functional API

枚举类是可调用的:

>>> Animal = Enum("Pet", "Tortoise CAT DOG")

完整的API如下:
Enum(value="NewEnumName", names=<...>, *, module="...", qualname="...", type=, start=1)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/42548.html

相关文章

  • Python入门细节

    摘要:入门细节相除后的类型双斜杠是整除,出来的类型是。序列,集合和字典属于组,是的基本数据类型。变量名区分大小写。尽量避免循环引入。变量函数等引入内指定的变量函数等。中如果没有出现模块名也是绝对导入。顶级包与入口文件的位置 python入门细节 相除后的类型 type(2/2) float type(2//2) int 双斜杠是整除,出来的类型是int。单斜杠的出来的是float类型。 进制...

    microcosm1994 评论0 收藏0
  • Pythonenum 模块源码分析

    摘要:起步上一篇的枚举类型文末说有机会的话可以看看它的源码。但这样的方式并不好,范围大,它包含该类的所有属性和方法。而不单单是枚举的命名空间。每个成员都有名称属性和值属性上述的代码中,取得的值是。 起步 上一篇 《Python 的枚举类型》 文末说有机会的话可以看看它的源码。那就来读一读,看看枚举的几个重要的特性是如何实现的。 要想阅读这部分,需要对元类编程有所了解。 成员名不允许重复 这部...

    muddyway 评论0 收藏0
  • python:基础知识

    摘要:与字符串不同,列表元素支持改写。元组比列表更加安全,因为不能修改集合一个功能是进行集合操作,另一个功能是消除重复的元素。 基本数据类型 数字 整型,浮点型,布尔型,复数 组 序列,集合,字典 1 组 # 序列-字符串 str 不可变类型 # 序列-列表 list [1,2,3,4,5,6,as] 可变类型 # 序列-元组 tuple (1,2,3,4,5,6,as) 不可变类型 ...

    xiongzenghui 评论0 收藏0
  • Python 的枚举类型

    摘要:起步的原生类型中并不包含枚举类型。枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表示某些特定的有限集合,例如星期月份状态等。简单的示例枚举成员有值默认可重复,枚举成员具有友好的字符串表示枚举类型不可实例化,不可更改。 起步 Python 的原生类型中并不包含枚举类型。为了提供更好的解决方案,Python 通过 PEP 435 在 3.4 版本中添加了 enum 标准库。 枚举...

    wall2flower 评论0 收藏0
  • Emscripten教程C++和JavaScript绑定(三)

    摘要:支持绑定大多数的结构,包括和中引入的。枚举支持枚举和枚举类。虽然还有进一步优化的空间,但到目前为止,它在实际应用程序中的性能已经被证明是完全可以接受的。 翻译:云荒杯倾 Embind用于绑定C++函数和类到JavaScript,这样编译代码就能在js中以一种很自然的方式来使用。Embind也支持从C++调JavaScript的class。 Embind支持绑定大多数C++的结构,包括C...

    warkiz 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<