目录
固定枚举类
- 枚举正确写法
- 相比普通类,枚举的优势
- 获取枚举值、枚举标签名、枚举类型
- 枚举类型与遍历
- 枚举类型与运算
- 枚举值相同时的特殊情况
- 枚举类型转换
- 枚举类的父类IntEnum
- @unique装饰器
- 拓展
- 闭包
一、固定枚举类
之前,学习的面向对象中的类,其实例化的对象是无限制的,例如,将学生类实例化,可以得到小明、小红、小刚...。
但是,现实世界有种特殊的类,其对象却是有限且固定的。例如,月份类的对象数目只能是1-12,星期类的对象数目只能是1-7。所以叫固定枚举类。
所以python3.4就新增Enum父类,专门描述固定枚举类。
其中,Enumerate:one by one
所以,枚举是之前面向对象编程中的普通类的一种补充。
1.枚举的正确写法
(1)一般写法:
用不同的数字表示不同的种类
例如:表示腾讯QQ的不同种类的会员?
1 绿钻
2 黄钻
3 红钻
4 黑钻
缺点:当别人看到数字时,是不知道其是什么类型的,不直接。也就是说,会破坏可读性。
(2)正确写法:
用标签名字,定义一组常量,以文字形式来表示不同的种类
from enum import Enum # Enum是个内置的类,且是父类(第六章)
class VIP(Enum): #所有的枚举类,都是Enum的子类
YELLOW = 1
GREEN = 2 #左边:有意义的标签名字 右边:没意义的取值
BLACK = 3 #左边:最好用大写,因为是常量 右边:只要不同就行,随便改
RED = 4
print(VIP.YELLOW)
-->
VIP.YELLOW #不是数字1?这正是枚举类的意义所在:重在标签名字
2.相比普通类,枚举的优势
(1)关于表示枚举类,常见的三种写法:
写法1:
通过模块中的全局变量来实现
yellow = 1
green = 2
写法2:
用数据结构字典dict来组织数据
{'yellow':1,'green':2} #如果不用枚举类,算是很好的一个表示种类的方式(最贴近枚举类)
写法3:
用类来封装数据
class TypeDiamond():
yellow = 1 #定义一个普通的类,将其作为类变量封装起来
green = 2
小结:
写法1的缺点,之前已分析
写法2与写法3的缺点:
- 可变
代码中可轻易更改它的值 - 没有防止相同标签的功能
可轻易重复
(2)枚举类的优势
优势1:不能更改枚举类的数值
from enum import Enum
class VIP(Enum): #枚举类
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen(): #普通的类
YELLOW = 1 #普通类下的类变量,随便改
print(VIP.YELLOW)
VIP.YELLOW = 6 #通过赋值,试试改下枚举类的数值
-->
error ❌ #优势1:不能更改枚举类,这是一种保护功能
优势2:不能重复使用相同的标签
from enum import Enum
class VIP(Enum):
YELLOW = 1
YEELOW = 2 #试试让两个标签名字相同
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
print(VIP.YELLOW)
VIP.YELLOW = 6
-->
error ❌ #不能重复使用标签名字
3.获取枚举值、枚举标签名、枚举类型
(1)如何获取枚举类型下面,某一个标签所对应的具体的数值?
用print(VIP.GREEN.value)
获取
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
print(VIP.GREEN.value) #枚举的值
-->
2
(2)如何获取枚举类型下面,某一个标签的名字?
用print(VIP.GREEN.name)
获取
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
print(VIP.GREEN.name) #枚举的名字
-->
GREEN
(3)如何获取枚举类型本身?
直接print(VIP.GREEN)
获取
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
print(VIP.GREEN) #枚举类型本身
-->
VIP.GREEN
(4)同样是GREEN,(2)与(3)有什么区别?
数据类型不一样。
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
print(type(VIP.GREEN.name))
print(type(VIP.GREEN))
-->
<class 'str'> #name只是标签的名字,所以是字符串
<enum 'VIP'> #整体表示枚举类型
(5)如何通过枚举标签的名称,获取枚举类型?
通过print(VIP['GREEN'])
获取,有点像字典的访问
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
print(VIP['GREEN'])
-->
VIP.GREEN
4.枚举类型与遍历
用for循环,遍历所有的枚举类型
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
for v in VIP:
print(v)
-->
VIP.YELLOW #遍历出了所有的枚举类型
VIP.GREEN
VIP.BLACK
VIP.RED
5.枚举类型与运算
(1)枚举类型之间支持等值比较运算
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
result = VIP.GREEN == VIP.BLACK #值是否相等
print(result)
-->
False #不相等
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
result = VIP.GREEN == VIP.GREEN #值是否相等
print(result)
-->
True #相等
当然,也可以是这样的等值比较:
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class VIP1(Enum): #成了枚举类型
YELLOW = 1
result = VIP.YELLOW == VIP1.YELLOW #值是否相等
print(result)
-->
False #不相等
注意:
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
result = VIP.GREEN == 2 #必须是两个枚举类之间进行比较,不能是数字int
print(result)
-->
False #虽不报错,但却是错误的❌
(2)枚举类型之间不支持大小比较的运算
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
result = VIP.GREEN >= VIP.BLACK #大小比较?
print(result)
-->
error ❌
(3)枚举类型之间支持身份运算
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 2
BLACK = 3
RED = 4
class Commen():
YELLOW = 1
result = VIP.GREEN is VIP.GREEN #身份是否相同
print(result)
-->
True
6.枚举类型的值相同时的特殊情况
由上可知,枚举类型的标签名称一定不能相同。那么,枚举类型的值能否相同呢?
值能相同,但会被python视为第一个标签的别名。
本质上,两者仍是同一种枚举类型。
(1)例题
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 1 #GREEN标签的值,跟第一个YELLOW标签的值,一样了
#本质上:YELLOW_ALIAS = 1
BLACK = 3
RED = 4
print(VIP.GREEN) #看下GREEN的枚举类型的变化
-->
VIP.YELLOW #既然两者一样,那就只保留大名YELLOW,剔除GREEN
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 1
BLACK = 3
RED = 4
for v in VIP: #用for循环遍历时
print(v)
-->
VIP.YELLOW
VIP.BLACK
VIP.RED #第二个值重复的枚举类型GREEN,不会被打印出来
(2)如果非要遍历打印出别名呢?
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 1
BLACK = 3
RED = 4
for v in VIP.__members__.items(): #使用内置变量__members__,并调用items方法
#⭐遍历字典时,也是用的该法(第几章)
print(v)
-->
('YELLOW', <VIP.YELLOW: 1>) #以元组的形式
('GREEN', <VIP.YELLOW: 1>) #别名的枚举类型,也打印出来了
('BLACK', <VIP.BLACK: 3>)
('RED', <VIP.RED: 4>) #看着有点复杂
或
from enum import Enum
class VIP(Enum):
YELLOW =
GREEN = 1
BLACK = 3
RED = 4
for v in VIP.__members__: #只使用内置变量__members__
print(v)
-->
YELLOW #精简
GREEN
BLACK
RED #不管值有没有重复,左边的“标签名称”都打印出来了
7.枚举转换
编写服务器代码时,要与数据库打交道。在数据库中,存取枚举类型两种方式:
- 一般存取具体的数值(数字)
- 也可以存取标签名字,将其以字符串的形式,存到数据库中某一字段中,以代表枚举类型。
建议第一种方式。
if a==1: #这里的1和2代表什么?虽然逻辑上没问题,但可读性差
print()
if a==2: #即使加上注释,也不建议该写法
print()
if a==VIP.YELLOW:
print()
if a==VIP.BLACK: #可读性好
print()
数据库已存数值(数字),代码也已定义枚举类。那么如何将数字转换成枚举类型?
from enum import Enum
class VIP(Enum):
YELLOW = 1
GREEN = 1
BLACK = 3
RED = 4
class common():
YELLOW = 1
a = 1
print(VIP(a)) #将数字传入到VIP()中即可 #既可以传左边标签名,又可以传右边数字
-->
VIP.YELLOW #打印出的是枚举类型
上述的将数字转换成枚举类型,并非真正数据类型的转换(str-->int),仅仅只是使用数值来访问对应的枚举类型。因此,只是视作转换。
8.枚举类的父类IntEnum
以前,枚举类的数值既可以是整型int,也可以是字符串str,更可以是其他。
但如果想强制要求只能是整型int呢?
枚举类的父类,除了Enum,还有IntEnum。
用途:限制枚举类型的数值只能是整型int
例题
from enmu import IntEnum
class VIP(IntEnum): #这里导入的父类是IntEnum
YELLOW = 1
GREEN = 'str' #只能是整型int
-->
error ❌
9.@unique装饰器
用途:限制每个不同的枚举类型,不能取相同的值
例题
from enum import Enum,unique
@unique
class VIP(Enum):
YELLOW = 1
GREEN = 1 #枚举类型的数值,跟上面一样
black = 3
-->
error ❌ #装饰器@unique规定,数值不能相同
10.拓展
枚举类型与单例模式
枚举类型的实现是一种单例模式,单例模式是23种设计模式之一。即它无法像普通的类一样实例化。
(1)设计模式的初衷:
- 防止代码频繁变化。
(2)设计模式的特点:
- 对团队成员要求高
- 初始成本高
- 其优势,日后很长时间才能凸显
(3)什么时候建议用设计模式,什么时候不用?
使用设计模式 | 不使用设计模式 | |
---|---|---|
产品,平台,服务 | 小项目 | |
生命周期很长 | 生命周期短 | |
纯粹靠业务逻辑支持,没太多技术含量的项目 |
业务变更,只需要改变一个变量即可。若套用设计模式,还要补充一个类。
所以,编程初期,不建议过分关注。
Comments | NOTHING