欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

一文读懂Python 枚举

程序员文章站 2022-04-21 11:23:51
enum 是一组绑定到唯一常数值的符号名称,并且具备可迭代性和可比较性的特性。我们可以使用 enum 创建具有良好定义的标识符,而不是直接使用魔法字符串或整数,也便于开发工程师的代码维护。创建枚举我们...

enum 是一组绑定到唯一常数值的符号名称,并且具备可迭代性和可比较性的特性。我们可以使用 enum 创建具有良好定义的标识符,而不是直接使用魔法字符串或整数,也便于开发工程师的代码维护。

创建枚举

我们可以使用 class 语法创建一个枚举类型,方便我们进行读写,另外,根据函数 api 的描述定义,我们可以创建一个 enum 的子类,如下:

from enum import enum

class httpstatus(enum):
  ok = 200
  bad_request = 400
  forbidden = 403
  not_found = 404
  request_timeout = 408
  service_unavailable = 500

注意: 枚举属性值可以是任何东西: int, str 等。如果确切的值不重要,您可以使用 auto 实例,并为您选择适当的值。如果您将 auto 与其他值混合,则必须小心。 枚举类型中,不可以设置相同名称的 name,可以有相同的 value。

enum 自带属性 namevalue,日常工作中使用最多的也是这两个属性,我们打印看看结果:

print('member: {}'.format(httpstatus.ok))        # member: httpstatus.ok
print('member name: {}'.format(httpstatus.ok.name))   # member name: ok
print('member value: {}'.format(httpstatus.ok.value))  # member value: 200
print(repr(httpstatus.ok))               # <enum 'httpstatus'>
print(type(httpstatus.ok))               # <httpstatus.ok: 200>
print(isinstance(httpstatus.ok, httpstatus))      # true

枚举迭代

枚举支持迭代和遍历顺序。举个例子:

from enum import enum, auto

# 创建
class httpstatus(enum):
  ok = 200
  bad_request = 400
  forbidden = 403
  not_found = 404
  request_timeout = 408
  service_unavailable = 500
  other = auto.value

# 迭代
for status in httpstatus:
  print('{} : {}'.format(status.name, status.value))

打印结果:

ok : 200
bad_request : 400
forbidden : 403
not_found : 404
request_timeout : 408
service_unavailable : 500
other : <object object at 0x000002863e1d7b10>

可以看出,遍历的每一个 status 是一个独立的枚举成员,拥有 namevalue 属性。

另外,我们也可以使用如下形式来进行枚举遍历:

for name, member in httpstatus.__members__.items():
  print('{} : {}'.format(name, member))

枚举成员与属性访问

通过枚举 value 进行访问,访问需要使用元组()的形式

print(httpstatus(200))   # httpstatus.ok

通过枚举 name 进行访问,访问需要使用列表[]的形式

print(httpstatus['ok'])   # httpstatus.ok

将属性赋予另一个 enum 成员

number = httpstatus.ok
print(number)        # httpstatus.ok

枚举值唯一

上面我们创建的枚举类中,value 值是可以重复的,如果我们不想枚举类中的值重复可以是用装饰器 @unique,举例如下:

from enum import enum, unique

# 创建
@unique
class httpstatus(enum):
  ok = 200
  bad_request = 400
  forbidden = 403
  not_found = 404
  request_timeout = 408
  service_unavailable = 500
  other = 200

我们运行后,报如下异常:

valueerror: duplicate values found in <enum 'httpstatus'>: other -> ok

我们查看源代码,发现加入此装饰器的枚举类型,unique 方法会将其 __members__.items() 进行遍历,追加到 duplicates 列表中,如果发现列表不为空,则抛出如上异常信息。

枚举自动赋值

此功能用于我们在使用枚举时,只在意枚举的标识符的含义而不在意值的情况下,但是如果需要与字符串或整数混合使用就要额外注意。下面贴上官方的示例:

import unittest
from enum import auto, enum

class testenum(unittest.testcase):
  
  def test_auto_number(self):
    class color(enum):
      red = auto()
      blue = auto()
      green = auto()
  
    self.assertequal(list(color), [color.red, color.blue, color.green])
    self.assertequal(color.red.value, 1)
    self.assertequal(color.blue.value, 2)
    self.assertequal(color.green.value, 3)
  
  def test_auto_name(self):
    class color(enum):
      def _generate_next_value_(self, start, count, last):
        return self
  
      red = auto()
      blue = auto()
      green = auto()
  
    self.assertequal(list(color), [color.red, color.blue, color.green])
    self.assertequal(color.red.value, 'red')
    self.assertequal(color.blue.value, 'blue')
    self.assertequal(color.green.value, 'green')

可以发现,使用 auto() 得到的是整数自增型,如果我们需要别的方式,只需要在我们的枚举类中,重写 _generate_next_value_ 方法。

枚举比较

枚举对象可以进行比较,但是不能进行值比较,如果需要进行值比较则需要枚举对象继承 intenum 对象,举个例子:

import unittest
from enum import enum, intenum

class testenum(unittest.testcase):
  class season(intenum):
    spring = 1
    summer = 2
    autumn = 3
    winter = 4

  def test_comparisons(self):
    season = self.season

    self.assertequal(season.spring, 1)

    class part(enum):
      spring = 1
      clip = 2
      barrel = 3
      
    self.assertnotequal(part.spring, 1)
    self.assertnotequal(part.spring, season.spring)

testenum().test_comparisons()

上面的测试例子当中,我们创建了两个继承类型不一样的枚举类,可以看到继承了 intenum season 可以进行值的比较,而继承了 enumpart 则不能进行值比较,并且 intenum 类型与 enum 类型也不能进行比较,即使属性和值一样。

枚举方法

枚举中可以定义枚举类自身特有的方法,也可以复写一些已经在基类中定义好的方法,比如: __init__, __str__, __repr__ , __hash__ ,__format__ 等。举个例子:

from enum import enum

class mood(enum):
  funky = (1, "hello")
  happy = (3, "world")

  def describe(self):
    return self.name, self.value

  def __init__(self, num, nice):
    self.num = num
    self.nice = nice

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

  @classmethod
  def favorite_mood(cls):
    return cls.happy

  @property
  def testvalue(self):
    return self.nice + ':' + str(self.num)

上面我们定义了一个枚举类,其中 value 是一个枚举类型,我们可以定义 __init__ 方法去对应元组中的值,我们也复写了 __str__ 方法。

打印方法看看效果:

print(mood.favorite_mood())   # my custom str! (3, 'world')
print(mood.happy.describe())  # ('happy', (3, 'world'))
print(str(mood.funky))     # my custom str! (1, 'hello')
print(mood.funky.testvalue)   # hello:1

从输出结果看,我们自定义和复写的方法都已经成功的应用到了 mood 类中。

枚举继承

不同于 java 中的枚举类, python 中的枚举类是可以被继承的,但是被继承的枚举类规定其不能定义任何成员,但可以定义抽象方法。举例如下:

class enumextend(unittest.testcase):

  def test_extending(self):
    class shade(enum):
      def shade(self):
        print(self.name)

    class color(shade):
      red = 1
      green = 2
      blue = 3
    with self.assertraises(typeerror):
      class morecolor(color):
        cyan = 4
        magenta = 5
        yellow = 6

  def test_extending2(self):
    class shade(enum):
      def shade(self):
        return self.name

    class color(shade):
      def hex(self):
        return '%s nice!' % self.value

    class morecolor(color):
      cyan = 4
      magenta = 5
      yellow = 6
    self.assertequal(morecolor.magenta.shade(), 'magenta')
    self.assertequal(morecolor.magenta.hex(), '5 nice!')

测试用例可以完美运行,我们可以发现:第一个方法中,抛出了 typeerror 的异常;第二个测试方法中,morecolor 继承了 color, color 继承了 shade, 并且我们可以通过子类调用父类中的方法。

总结

本节主要介绍了 enum 模块的基础知识,包含枚举的创建、枚举成员和属性的访问、枚举方法的创建、枚举的继承等。其中新版中的 _ignore_、_order_、_missing_ 等可以学习官网的例子,另外 enum 的子类 intenum、intflag等也是我们比较常用的枚举基类,本文中简单的介绍了 intenum, 而 intflag 相比与 intenum 多了 &, |, ^, ~ 的操作,其他的子类大家感兴趣也可以了解。

代码地址

示例代码:python-100-days-day036

以上就是一文读懂python 枚举的详细内容,更多关于python 枚举的资料请关注其它相关文章!

相关标签: python 枚举