Python 枚举

发布时间:2019-08-24 09:22:56编辑:auto阅读(1645)

    1. 枚举的定义

    首先,定义枚举要导入enum模块。
    枚举定义用class关键字,继承Enum类。
    用于定义枚举的class和定义类的class是有区别。

    示例代码:

    from enum import Enum
    
    class Color(Enum):
        red = 1
        orange = 2
        yellow = 3
        green = 4
        blue = 5
        indigo = 6
        purple = 7

    代码分析:

    1. 上面的代码,我们定义了颜色的枚举Color.
    2. 颜色枚举有7个成员,分别是Color.red、Color.orange、Color.yellow等。
    3. 每一个成员都有它们各自名称和值,Color.red成员的名称是:red,值是:1。
    4. 每个成员的数据类型就是它所属的枚举。【*注:用class定义的类,实际上就是一种类型】

    1.1 定义枚举时,成员名称不允许重复

    from enum import Enum
    
    class Color(Enum):
        red = 1
        red = 2

    上面的代码,就无法执行。提示错误:TypeError: Attempted to reuse key: ‘red’

    1.2 默认情况下,不同的成员值允许相同。但是两个相同值的成员,第二个成员的名称被视作第一个成员的别名

    from enum import Enum
    
    class Color(Enum):
        red = 1
        red_alias = 1

    成员Color.red和Color.red_alias具有相同的值,那么成员Color.red_alias的名称red_alias就被视作成员Color.red名称red的别名。

    1.3 如果枚举中存在相同值的成员,在通过值获取枚举成员时,只能获取到第一个成员

    from enum import Enum
    
    class Color(Enum):
        red = 1
        red_alias = 1
    
    print(Color(1))

    输出结果为:Color.red

    1.4 如果要限制定义枚举时,不能定义相同值的成员。可以使用装饰器@unique【要导入unique模块】

    from enum import Enum, unique
    
    
    @unique
    class Color(Enum):
        red = 1
        red_alias = 1

    再执行就会提示错误:ValueError: duplicate values found in

    2. 枚举取值

    2.1 通过成员的名称来获取成员

    Color['red']

    2.2 通过成员值来获取成员

    Color(2)

    2.3 通过成员,来获取它的名称和值

    red_member = Color.red
    red_member.name
    red_member.value

    3. 迭代器

    3.1 枚举支持迭代器,可以遍历枚举成员

    for color in Color:
        print(color)

    输出结果是,枚举的所有成员。Color.red、Color.orange、Color.yellow、Color.green、Color.blue、Color.indigo、Color.purple。

    3.2 如果枚举有值重复的成员,循环遍历枚举时只获取值重复成员的第一个成员

    from enum import Enum
    
    
    class Color(Enum):
        red = 1
        orange = 2
        yellow = 3
        green = 4
        blue = 5
        indigo = 6
        purple = 7
        red_alias = 1
    
    
    for color in Color:
        print(color)

    输出结果是:Color.red、Color.orange、Color.yellow、Color.green、Color.blue、Color.indigo、Color.purple。但是Color.red_alias并没有出现在输出结果中。

    3.3 如果想把值重复的成员也遍历出来,要用枚举的一个特殊属性__members__

    from enum import Enum
    
    class Color(Enum):
        red = 1
        orange = 2
        yellow = 3
        green = 4
        blue = 5
        indigo = 6
        purple = 7
        red_alias = 1
    
    
    for color in Color.__members__.items():
        print(color)

    输出结果:(‘red’,

    4. 枚举比较

    4.1 枚举成员可进行同一性比较

    Color.red is Color.red

    输出结果是:True

    Color.red is not Color.blue

    输出结果是:True

    4.2 枚举成员可进等值比较

    Color.blue == Color.red

    输出结果是:False

    Color.blue != Color.red

    输出结果是:True

    4.3 枚举成员不能进行大小比较

    Color.red < Color.blue

    输出结果出错:TypeError: unorderable types: Color() < Color()


    # 枚举类 Enum
    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():
        # value属性则是自动赋给成员的int常量,默认从1开始计数
        print(name,'=>',member,',',member.value) 
    
    # 输出结果
    # Jan => Month.Jan , 1
    # Feb => Month.Feb , 2
    # Mar => Month.Mar , 3
    # Apr => Month.Apr , 4
    # May => Month.May , 5
    # Jun => Month.Jun , 6
    # Jul => Month.Jul , 7
    # Aug => Month.Aug , 8
    # Sep => Month.Sep , 9
    # Oct => Month.Oct , 10
    # Nov => Month.Nov , 11
    # Dec => Month.Dec , 12
    
    # 如果需要更精确地控制枚举类型,可以从Enum派生出自定义类
    from enum import Enum,unique
    
    @unique
    class WeekDay(Enum):
        Sun = 0 #设置sun 的value为0
        Mon = 1
        Tue = 2
        Wed = 3
        Thu = 4
        Fri = 5
        Sat = 6
        # Sat = 6 # 如果重复会报错 TypeError: Attempted to reuse key: 'Sat'
        # @unique装饰器可以帮助我们检查保证没有重复值
    
    # 访问这些枚举类型可以有若干种方法:
    day1 = WeekDay.Mon
    print(day1) # WeekDay.Mon
    
    print(WeekDay.Thu) # WeekDay.Thu
    
    print(WeekDay['Tue']) # WeekDay.Tue
    
    print(WeekDay.Tue.value) # 2
    
    print(day1 == WeekDay.Mon) # True
    
    print(day1 == WeekDay.Sun) # False
    
    print(WeekDay(1)) # WeekDay.Mon
    
    print(day1 == WeekDay(1)) # True
    
    print(Weekday(7)) # NameError: name 'Weekday' is not defined

    python type()动态创建类

    type()函数可以查看一个类型或变量的类型,Hello是一个class,它的类型就是type,而h是一个实例,它的类型就是class Hello。

    我们说class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。

    type()函数既可以返回一个对象的类型,又可以创建出新的类型,比如,我们可以通过type()函数创建出Hello类,而无需通过class Hello(object)…的定义:

    def fn(self,name='world'):
        print('hello,%s.' % name)
    Hello = type('Hello',(object,),dict(hello=fn))
    h = Hello()
    
    h.hello() # hello world.
    
    h.hello('py') # hello py.
    
    print(type(Hello)) # <class 'type'>
    
    print(type(h)) # <class '__main__.Hello'>

    要创建一个class对象,type()函数依次传入3个参数:

    class的名称;
    继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
    class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
    通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。

    正常情况下,我们都用class Xxx…来定义类,但是,type()函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。

关键字