python面向对象-枚举类

下面截图,是某系统中修改员工信息页面的截图,其中“性别”、“工作类型”、“职位”有固定的值,不允许填写,实现雇员类Employee,定义属性、getter、setter方法和上述的固定值
http://www.malaoshi.top/upload/0/0/1EF2Hke6JzOB.png

提示:

雇员类中有name、gender、birthday、work_type、post等属性,其中gender有固定值,或者男或者女,同理work_type、post也是有固定值

代码

#coding=utf-8

class Employee:

    def __init__(self):
        self._name=None
        self._gender=None
        self._birthday=None
        self._work_type=None
        self._post=None

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self,name):
        self._name=name

    @property
    def gender(self):
        return self._gender

    @gender.setter
    def gender(self,gender):
        self._gender=gender


    @property
    def birthday(self):
        return self._birthday

    @birthday.setter
    def birthday(self,birthday):
        self._birthday=birthday

    @property
    def work_type(self):
        return self._work_type

    @work_type.setter
    def work_type(self,work_type):
        self._work_type=work_type

    @property
    def post(self):
        return self._post

    @post.setter
    def post(self,post):
        self._post=post

调用

zhangsan=Employee()
zhangsan.name='张三'
zhangsan.birthday='1997-07-01'
zhangsan.gender='男'
zhangsan.work_type='全职'
zhangsan.post='员工'

print(zhangsan.name)
print(zhangsan.birthday)
print(zhangsan.gender)
print(zhangsan.work_type)
print(zhangsan.post)

缺点

gender、work_type、post有固定的值,但没有说明,在赋值时,可以随便指定,这显然是不合理的

优化代码

在Employee类中增加类属性,保存固定值。
在python中,变量名全大写,多个单词中间是下划线_,表示常量(python中没有真正的常量)。
规范参见:
http://www.malaoshi.top/show_1EF2DP94Jt0u.html

思考:
为什么是类属性,而不是全局变量

代码:

#coding=utf-8

class Employee:
    GENDER_MALE='男'
    GENDER_FEMALE='女'
    WORKTYPE_FULLTIME='全职'
    WORKTYPE_PARTTIME='兼职'
    POST_MANAGER='餐厅经理'
    POST_DEPUTY_MGR='副经理'
    POST_PROBATION_MGR='见习经理'
    POST_TRAINER='训练员'
    POST_EMP='员工'

    def __init__(self):
        self._name=None
        self._gender=None
        self._birthday=None
        self._work_type=None
        self._post=None

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self,name):
        self._name=name

    @property
    def gender(self):
        return self._gender

    @gender.setter
    def gender(self,gender):
        self._gender=gender


    @property
    def birthday(self):
        return self._birthday

    @birthday.setter
    def birthday(self,birthday):
        self._birthday=birthday

    @property
    def work_type(self):
        return self._work_type

    @work_type.setter
    def work_type(self,work_type):
        self._work_type=work_type

    @property
    def post(self):
        return self._post

    @post.setter
    def post(self,post):
        self._post=post

调用

zhangsan=Employee()
zhangsan.name='张三'
zhangsan.birthday='1997-07-01'
zhangsan.gender=Employee.GENDER_MALE
zhangsan.work_type=Employee.WORKTYPE_FULLTIME
zhangsan.post=Employee.POST_EMP

print(zhangsan.name)
print(zhangsan.birthday)
print(zhangsan.gender)
print(zhangsan.work_type)
print(zhangsan.post)

总结

好处是简单
缺点是类型是string,并且是变量

python中没有常量

枚举类型

为了解决上面问题,更好的方法是定义一个class,在class中定义常量,保存固定值。

Python提供了Enum类(枚举类型)来实现这个功能

语法

  1. 定义子类,继承Enum父类
  2. 类属性就是枚举成员

代码:

from enum import Enum
class Gender(Enum):
    male = '男'
    female = '女'

缺点:
枚举值可能重复

如果重复,遍历时不会显示

不让枚举值重复

通过装饰器@unique校验枚举值是否重复,重复会报错

from enum import Enum, unique
#装饰器检验male、female的值是否重复
@unique
class Gender(Enum):
    male = '男'
    female = '女'

使用枚举类型

查看类型
print(type(Gender.male))
1. 获取成员

通过类名.属性名和类名.['属性名']获取

#获取成员
print(Gender.male)
print(Gender['male'])
2. 获取成员名

通过类名.属性名.name和类名.['属性名'].name获取

#获取成员名
print(Gender.male.name)
print(Gender['male'].name)
3. 获取成员值

通过类名.属性名.value和类名.['属性名'].value获取

#获取成员值
print(Gender.male.value)
print(Gender['male'].value)

赋值报错

Gender.male='123'

执行报错,如下:

AttributeError: Cannot reassign members.

遍历枚举

for name, member in Gender.__members__.items():
    print(name, ',', member, ',', member.value)

枚举的简写

from enum import Enum
class Employee:
    gender = Enum('Gender', ('male', 'female'))

print(Employee.gender.male.value)
print(Employee.gender.female.value)

value属性自动赋int常量,默认从1开始

本文开头问题的后续代码

@unique
class WorkType(Enum):
    full_time = '全职' 
    part_time = '兼职'
@unique
class Post(Enum):
    manager='餐厅经理'
    deputy_mgr='副经理'
    probation_mgr='见习经理'
    trainer='训练员'
    emp='员工'
class Employee:

    def __init__(self):
        self._name=None
        self._gender=None
        self._birthday=None
        self._work_type=None
        self._post=None

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self,name):
        self._name=name

    @property
    def gender(self):
        return self._gender

    @gender.setter
    def gender(self,gender):
        self._gender=gender


    @property
    def birthday(self):
        return self._birthday

    @birthday.setter
    def birthday(self,birthday):
        self._birthday=birthday

    @property
    def work_type(self):
        return self._work_type

    @work_type.setter
    def work_type(self,work_type):
        self._work_type=work_type

    @property
    def post(self):
        return self._post

    @post.setter
    def post(self,post):
        self._post=post

执行

zhangsan=Employee()
zhangsan.name='张三'
zhangsan.birthday='1997-07-01'
zhangsan.gender=Gender.male.value
zhangsan.work_type=WorkType.full_time.value
zhangsan.post=Post.emp.value

print(zhangsan.name)
print(zhangsan.birthday)
print(zhangsan.gender)
print(zhangsan.work_type)
print(zhangsan.post)

总结

  1. 定义子类,继承Enum父类
  2. 类属性是枚举成员
  3. 枚举成员定以后不可再赋值
  4. @unique装饰器不允许枚举值重复

原文出处:/show_1EF2HlsIRhKS.html