• 枚举类


    枚举类的使用

    实际开发中,我们离不开定义常量,当我们需要定义常量时,其中一个办法是用大写变量通过整数来定义,例如月份:

    JAN = 1
    FEB = 2
    MAR = 3
    ...
    NOV = 11
    DEC = 12

    当然这样做简单快捷,缺点是类型是 int ,并且仍然是变量。

    那有没有什么好的方法呢?

    这时候我们定义一个 class 类型,每个常量都是 class 里面唯一的实例。

    正好 Python 提供了 Enum 类来实现这个功能如下:

    #!/usr/bin/env python3
    # -*- coding: UTF-8 -*-
    
    from enum import Enum
    
    Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
    
    # 遍历枚举类型
    for name, member in Month.__members__.items():
        print(name, '---------', member, '----------', member.value)
    
    # 直接引用一个常量
    print('
    ', Month.Jan)

    输出的结果如下:

    我们使用 Enum 来定义了一个枚举类。

    上面的代码,我们创建了一个有关月份的枚举类型 Month ,这里要注意的是构造参数,第一个参数 Month 表示的是该枚举类的类名,第二个 tuple 参数,表示的是枚举类的值;当然,枚举类通过 __members__ 遍历它的所有成员的方法。

    注意的一点是 , member.value 是自动赋给成员的 int 类型的常量,默认是从 1 开始的。

    而且 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改

    Enum 的源码

    通过上面的实例可以知道通过 __members__ 可以遍历枚举类的所有成员。

    那有没有想过为什么呢?

    当你看到那段代码的时候,有没有想过为什么通过 __members__ 就能遍历枚举类型的所有成员出来?

    我们可以先来大致看看 Enum 的源码是如何实现的;

    Enum 在模块 enum.py 中,先来看看 Enum 类的片段

    class Enum(metaclass=EnumMeta):
        """Generic enumeration.
        Derive from this class to define new enumerations.
        """

    可以看到,Enum 是继承元类 EnumMeta 的;再看看 EnumMeta 的相关片段

    class EnumMeta(type):
        """Metaclass for Enum"""
        @property
        def __members__(cls):
            """Returns a mapping of member name->value.
            This mapping lists all enum members, including aliases. Note that this
            is a read-only view of the internal mapping.
            """
            return MappingProxyType(cls._member_map_)

    首先 __members__ 方法返回的是一个包含一个 Dict 既 Map 的 MappingProxyType,并且通过 @property 将方法 __members__(cls) 的访问方式改变为了变量的的形式,那么就可以直接通过 __members__ 来进行访问了

    枚举的比较

    因为枚举成员不是有序的,所以它们只支持通过标识(identity) 和相等性 (equality) 进行比较。下面来看看 ==is 的使用:

    #!/usr/bin/env python3
    # -*- coding: UTF-8 -*-
    from enum import Enum
    
    
    class User(Enum):
        Twowater = 98
        Liangdianshui = 30
        Tom = 12
    
    
    Twowater = User.Twowater
    Liangdianshui = User.Liangdianshui
    
    print(Twowater == Liangdianshui, Twowater == User.Twowater)
    print(Twowater is Liangdianshui, Twowater is User.Twowater)
    
    try:
        print('
    '.join('  ' + s.name for s in sorted(User)))
    except TypeError as err:
        print(' Error : {}'.format(err))

    输出的结果:

    
    False True
    False True
     Error : '<' not supported between instances of 'User' and 'User'
    
    

    可以看看最后的输出结果,报了个异常,那是因为大于和小于比较运算符引发 TypeError 异常。也就是 Enum 类的枚举是不支持大小运算符的比较的。

    那么能不能让枚举类进行大小的比较呢?

    当然是可以的,使用 IntEnum 类进行枚举,就支持比较功能。

    #!/usr/bin/env python3
    # -*- coding: UTF-8 -*-
    import enum
    
    
    class User(enum.IntEnum):
        Twowater = 98
        Liangdianshui = 30
        Tom = 12
    
    
    try:
        print('
    '.join(s.name for s in sorted(User)))
    except TypeError as err:
        print(' Error : {}'.format(err))
    

    看看输出的结果:

    Tom
    Liangdianshui
    Twowater
    

    通过输出的结果可以看到,枚举类的成员通过其值得大小进行了排序。也就是说可以进行大小的比较。

  • 相关阅读:
    【转】滑动窗口与拥塞控制
    LeetCode 34 :Find First and Last Position of Element in Sorted Array
    主要电商模式介绍
    使用springboot创建邮件服务器
    解决Windows下端口占用问题
    [leetcode]给定二维平面上的n个点,找出位于同一直线上的点的最大数目
    获得超类的泛型参数在子类实例化传入的实际类型
    构造单例的五种方法
    20162308 2017-2018-2 《程序设计与数据结构》第11周学习总结
    20162308 2017-2018-2 《程序设计与数据结构》第十周学习总结
  • 原文地址:https://www.cnblogs.com/hrnn/p/13324948.html
Copyright © 2020-2023  润新知