4 道练习题·预计 40 分钟·做对一题解锁下一段
2019年10月14日16:59:38 看了一下,还有五个章节就修改完基础部分了。
干就完事了。
这一篇的目录如下:
实际开发中,我们离不开定义常量,当我们需要定义常量时,其中一个办法是用大写变量通过整数来定义,例如月份:
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('\n', Month.Jan)
输出的结果如下:
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
Month.Jan我们使用 Enum 来定义了一个枚举类。
上面的代码,我们创建了一个有关月份的枚举类型 Month ,这里要注意的是构造参数,第一个参数 Month 表示的是该枚举类的类名,第二个 tuple 参数,表示的是枚举类的值;当然,枚举类通过 __members__ 遍历它的所有成员的方法。
注意的一点是 , member.value 是自动赋给成员的 int 类型的常量,默认是从 1 开始的。
而且 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改
我们想给学习任务标上「待学习」或「已完成」。用枚举把允许的状态列清楚,再分开观察成员名和值:
from enum import Enum
class StudyState(Enum):
TODO = '待学习'
DONE = '已完成'
print(StudyState.TODO.name)
print(StudyState.TODO.value)
print(StudyState('已完成') is StudyState.DONE)输出:
TODO
待学习
TrueTODO 是成员的名称,'待学习' 是这里给它安排的值。StudyState('已完成') 按值寻找成员,不是在创建一个任意内容的新状态。
自己试试一个没有定义过的值,观察 ValueError;再比较 StudyState.TODO == '待学习',结果为 False,因为这里的普通 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__ 来进行访问了
请用 from ... import 从 enum 模块导入 Enum,然后:
Enum 的类 Color,包含三个成员:
RED = 1GREEN = 2BLUE = 3print(Color.RED)输出应该是:
Color.RED提示:直接
类名.成员名这种格式。
推荐一个,全网最全最友好的中文 AI 编程指南: coding.stormzhang.ai