# py-enum
A python enum module for python2.7 and django choices fields.
通过改造python3中的enum.py而来,增加对python2的支持,并新增类`ChoiceEnum`用于以下场景:
- argparse使用 `add_argument` 的参数 `choices`
- Django中 `models.CharField` 的参数 `choices`
- Django REST framework `ChoiceField` 的参数 `choices`
## 1. 安装
pip install py-enum
可查看版本变更记录[ChangeLog](https://github.com/SkylerHu/py-enum/blob/master/docs/CHANGELOG-1.x.md)
## 2. 使用(Usage)
### 2.1 用ChoiceEnum定义枚举
```python
# 导入
from py_enum import ChoiceEnum, unique
# 定义
class Color(ChoiceEnum):
RED = (1, '红色')
GREEN = (2, '绿色')
BLUE = (3, '蓝色', {'value': 'blue'})
@unique
class Status(ChoiceEnum):
PROCESSING = ('processing', '处理中')
APPROVED = ('approved', '已审批')
CANCELED = ('canceled', '已取消')
CLOSED = ('closed', '已关闭')
```
定义如上,按照`Key = (value, label, extra)`的形式进行定义,value定义的值;label是对值的描述;第三个参数是extra,额外信息,可以任意类型。
### 2.2 基础用法
- `直接根据Key访问value值`,而并不是一个tuple,正是和原生Enum的区别
- get_label方法
- get_extra方法
- `直接遍历枚举类`,这是能够作为Choices Enum的关键
```python
print(Color.RED) # 1
type(Color.RED) # <enum 'Color'>
len(colors) == 3 # true
Color.RED in Color # true
1 in Color # true
0 not in Color # true
Color.get_label(Color.RED) # '红色'
Color.get_extra(Color.BLUE) # {'value': 'blue'}
for value, label in Color:
print(value, label) # 直接遍历value和label
# 1, '红色'
# 2, '绿色'
# 3, '蓝色'
Color.to_js_enum()
# 输出dict数据,可以通过接口序列化后给前端使用,结合js-enumerate前端枚举库
"""
[
{"key": "RED", "value": 1, "label": "红色"},
{"key": "GREEN", "value": 2, "label": "绿色"},
{"key": "BLUE", "value": 3, "label": "蓝色", "extra": {"value": "blue"}}
]
"""
```
### 2.3 枚举对象实例化
```python
member = Color(Color.RED) # 或者 Color(1)
member.value == 1 # true
member.name == 'RED' # true
member.label == '红色' # true
member.option == (1, '红色') # true
member.extra == None # true,因为没有定义
# 以上几个属性无法修改,直接赋值会抛出AttributeError异常
member.value in Color # true
```
### 2.4 在Python argparse中使用
```python
import argparse
parser = argparse.ArgumentParser(description='test ChoiceEnum use in argparse.')
parser.add_argument('--color', type=int, choices=Color, required=True)
args = parser.parse_args(['--color', str(Color.RED)])
# args.color == Color.RED
```
### 2.5 在Django中使用
```python
from django.db import models
class ColorModel(models.Model):
color = models.IntegerField(verbose_name='颜色', choices=Color, default=Color.RED)
instance = ColorModel.objects.create()
assert instance.color == colors.RED
instance.color = colors.BLUE
instance.save()
```
### 2.6 在DRF中使用
```python
from rest_framework import serializers
class ColorSerializer(serializers.Serializer):
color = serializers.ChoiceField(help_text='选择颜色', choices=Color, default=Color.RED)
s = ColorSerializer()
s = ColorSerializer(data={'status': status.CLOSED})
assert s.is_valid() is True
s = ColorSerializer(data={'status': 1})
assert s.is_valid() is True
s = ColorSerializer(data={'status': 0})
assert s.is_valid() is False # 值不在枚举定义范围内,校验不通过
```
### 2.7 类Enum和unique
和python3中原生的Enum并无太大区别,具体可以参考[官方原生开发文档](https://docs.python.org/3.6/library/enum.html)
```python
from py_enum import Enum, unique
@unique
class Season(Enum):
SPRING = 1
SUMMER = 2
AUTUMN = 3
WINTER = 4
```
## 3. 对比
- `Enum`可以在`Python2`中使用,但需要注意的是:
- members无序,属性定义时申明的顺序和直接遍历枚举对象时并不一定一致;需通过`_order_`来定义member的顺序
- python2没有定义__bool__,所以不能直接用class类或者member来做逻辑判断
- 执行 Season.SPRING > Season.SUMMER 不会报错,但结果也不符合预期
- py3执行会raise TypeError, 不允许比较
- 但是ChoiceEnum是直接取值,可以用来做比较运算
- 枚举类定义时,无法识别多个相同的Key
- 在多继承方面会受限
- `Enum`和Python3原生enum.py对比,保留了`Enum`类和`unique`方法
- `ChoiceEnum`和Django的 models.Choices 的优势在于低版本Django也能使用,且普通Python项目脚本也能使用
- 新增了额外的特性
- 额外多出了`ChoiceEnum.extra`的用法,对不同枚举成员做映射配置相关场景可以使用
- 增加方法`ChoiceEnum.to_js_enum`返回数组数据,可以用于前端枚举库 [js-enumerate](https://github.com/SkylerHu/js-enum) 初始化使用
Raw data
{
"_id": null,
"home_page": "https://github.com/SkylerHu/py-enum.git",
"name": "py-enum",
"maintainer": null,
"docs_url": null,
"requires_python": ">=2.7",
"maintainer_email": null,
"keywords": null,
"author": "SkylerHu",
"author_email": "skylerhu@qq.com",
"download_url": "https://files.pythonhosted.org/packages/45/cc/79712e9b5e70ed4dcf0773f3a40ff7d40df1e0d3cf3f81042b6ade06fbc7/py-enum-1.1.1.tar.gz",
"platform": "any",
"description": "# py-enum\nA python enum module for python2.7 and django choices fields.\n\n\u901a\u8fc7\u6539\u9020python3\u4e2d\u7684enum.py\u800c\u6765\uff0c\u589e\u52a0\u5bf9python2\u7684\u652f\u6301\uff0c\u5e76\u65b0\u589e\u7c7b`ChoiceEnum`\u7528\u4e8e\u4ee5\u4e0b\u573a\u666f\uff1a\n- argparse\u4f7f\u7528 `add_argument` \u7684\u53c2\u6570 `choices`\n- Django\u4e2d `models.CharField` \u7684\u53c2\u6570 `choices`\n- Django REST framework `ChoiceField` \u7684\u53c2\u6570 `choices`\n\n\n## 1. \u5b89\u88c5\n\n\tpip install py-enum\n\n\u53ef\u67e5\u770b\u7248\u672c\u53d8\u66f4\u8bb0\u5f55[ChangeLog](https://github.com/SkylerHu/py-enum/blob/master/docs/CHANGELOG-1.x.md)\n\n## 2. \u4f7f\u7528(Usage)\n\n### 2.1 \u7528ChoiceEnum\u5b9a\u4e49\u679a\u4e3e\n\n```python\n# \u5bfc\u5165\nfrom py_enum import ChoiceEnum, unique\n\n# \u5b9a\u4e49\nclass Color(ChoiceEnum):\n RED = (1, '\u7ea2\u8272')\n GREEN = (2, '\u7eff\u8272')\n BLUE = (3, '\u84dd\u8272', {'value': 'blue'})\n\n@unique\nclass Status(ChoiceEnum):\n PROCESSING = ('processing', '\u5904\u7406\u4e2d')\n APPROVED = ('approved', '\u5df2\u5ba1\u6279')\n CANCELED = ('canceled', '\u5df2\u53d6\u6d88')\n CLOSED = ('closed', '\u5df2\u5173\u95ed')\n```\n\u5b9a\u4e49\u5982\u4e0a\uff0c\u6309\u7167`Key = (value, label, extra)`\u7684\u5f62\u5f0f\u8fdb\u884c\u5b9a\u4e49\uff0cvalue\u5b9a\u4e49\u7684\u503c\uff1blabel\u662f\u5bf9\u503c\u7684\u63cf\u8ff0\uff1b\u7b2c\u4e09\u4e2a\u53c2\u6570\u662fextra\uff0c\u989d\u5916\u4fe1\u606f\uff0c\u53ef\u4ee5\u4efb\u610f\u7c7b\u578b\u3002\n\n### 2.2 \u57fa\u7840\u7528\u6cd5\n- `\u76f4\u63a5\u6839\u636eKey\u8bbf\u95eevalue\u503c`\uff0c\u800c\u5e76\u4e0d\u662f\u4e00\u4e2atuple\uff0c\u6b63\u662f\u548c\u539f\u751fEnum\u7684\u533a\u522b\n- get_label\u65b9\u6cd5\n- get_extra\u65b9\u6cd5\n- `\u76f4\u63a5\u904d\u5386\u679a\u4e3e\u7c7b`\uff0c\u8fd9\u662f\u80fd\u591f\u4f5c\u4e3aChoices Enum\u7684\u5173\u952e\n\n```python\nprint(Color.RED) # 1\ntype(Color.RED) # <enum 'Color'>\nlen(colors) == 3 # true\nColor.RED in Color # true\n1 in Color # true\n0 not in Color # true\n\nColor.get_label(Color.RED) # '\u7ea2\u8272'\nColor.get_extra(Color.BLUE) # {'value': 'blue'}\n\nfor value, label in Color:\n print(value, label) # \u76f4\u63a5\u904d\u5386value\u548clabel\n# 1, '\u7ea2\u8272'\n# 2, '\u7eff\u8272'\n# 3, '\u84dd\u8272'\n\nColor.to_js_enum()\n# \u8f93\u51fadict\u6570\u636e\uff0c\u53ef\u4ee5\u901a\u8fc7\u63a5\u53e3\u5e8f\u5217\u5316\u540e\u7ed9\u524d\u7aef\u4f7f\u7528\uff0c\u7ed3\u5408js-enumerate\u524d\u7aef\u679a\u4e3e\u5e93\n\"\"\"\n[\n {\"key\": \"RED\", \"value\": 1, \"label\": \"\u7ea2\u8272\"},\n {\"key\": \"GREEN\", \"value\": 2, \"label\": \"\u7eff\u8272\"},\n {\"key\": \"BLUE\", \"value\": 3, \"label\": \"\u84dd\u8272\", \"extra\": {\"value\": \"blue\"}}\n]\n\"\"\"\n```\n\n### 2.3 \u679a\u4e3e\u5bf9\u8c61\u5b9e\u4f8b\u5316\n```python\nmember = Color(Color.RED) # \u6216\u8005 Color(1)\nmember.value == 1 # true\nmember.name == 'RED' # true\nmember.label == '\u7ea2\u8272' # true\nmember.option == (1, '\u7ea2\u8272') # true\nmember.extra == None # true\uff0c\u56e0\u4e3a\u6ca1\u6709\u5b9a\u4e49\n# \u4ee5\u4e0a\u51e0\u4e2a\u5c5e\u6027\u65e0\u6cd5\u4fee\u6539\uff0c\u76f4\u63a5\u8d4b\u503c\u4f1a\u629b\u51faAttributeError\u5f02\u5e38\nmember.value in Color # true\n```\n\n### 2.4 \u5728Python argparse\u4e2d\u4f7f\u7528\n```python\nimport argparse\n\nparser = argparse.ArgumentParser(description='test ChoiceEnum use in argparse.')\nparser.add_argument('--color', type=int, choices=Color, required=True)\nargs = parser.parse_args(['--color', str(Color.RED)])\n# args.color == Color.RED\n```\n\n### 2.5 \u5728Django\u4e2d\u4f7f\u7528\n```python\nfrom django.db import models\n\nclass ColorModel(models.Model):\n color = models.IntegerField(verbose_name='\u989c\u8272', choices=Color, default=Color.RED)\n\ninstance = ColorModel.objects.create()\nassert instance.color == colors.RED\ninstance.color = colors.BLUE\ninstance.save()\n```\n\n### 2.6 \u5728DRF\u4e2d\u4f7f\u7528\n```python\nfrom rest_framework import serializers\n\nclass ColorSerializer(serializers.Serializer):\n color = serializers.ChoiceField(help_text='\u9009\u62e9\u989c\u8272', choices=Color, default=Color.RED)\n\ns = ColorSerializer()\ns = ColorSerializer(data={'status': status.CLOSED})\nassert s.is_valid() is True\ns = ColorSerializer(data={'status': 1})\nassert s.is_valid() is True\ns = ColorSerializer(data={'status': 0})\nassert s.is_valid() is False # \u503c\u4e0d\u5728\u679a\u4e3e\u5b9a\u4e49\u8303\u56f4\u5185\uff0c\u6821\u9a8c\u4e0d\u901a\u8fc7\n```\n\n### 2.7 \u7c7bEnum\u548cunique\n\u548cpython3\u4e2d\u539f\u751f\u7684Enum\u5e76\u65e0\u592a\u5927\u533a\u522b\uff0c\u5177\u4f53\u53ef\u4ee5\u53c2\u8003[\u5b98\u65b9\u539f\u751f\u5f00\u53d1\u6587\u6863](https://docs.python.org/3.6/library/enum.html)\n\n```python\nfrom py_enum import Enum, unique\n\n@unique\nclass Season(Enum):\n SPRING = 1\n SUMMER = 2\n AUTUMN = 3\n WINTER = 4\n```\n\n## 3. \u5bf9\u6bd4\n- `Enum`\u53ef\u4ee5\u5728`Python2`\u4e2d\u4f7f\u7528\uff0c\u4f46\u9700\u8981\u6ce8\u610f\u7684\u662f\uff1a\n - members\u65e0\u5e8f\uff0c\u5c5e\u6027\u5b9a\u4e49\u65f6\u7533\u660e\u7684\u987a\u5e8f\u548c\u76f4\u63a5\u904d\u5386\u679a\u4e3e\u5bf9\u8c61\u65f6\u5e76\u4e0d\u4e00\u5b9a\u4e00\u81f4\uff1b\u9700\u901a\u8fc7`_order_`\u6765\u5b9a\u4e49member\u7684\u987a\u5e8f\n - python2\u6ca1\u6709\u5b9a\u4e49__bool__\uff0c\u6240\u4ee5\u4e0d\u80fd\u76f4\u63a5\u7528class\u7c7b\u6216\u8005member\u6765\u505a\u903b\u8f91\u5224\u65ad\n - \u6267\u884c Season.SPRING > Season.SUMMER \u4e0d\u4f1a\u62a5\u9519\uff0c\u4f46\u7ed3\u679c\u4e5f\u4e0d\u7b26\u5408\u9884\u671f\n - py3\u6267\u884c\u4f1araise TypeError, \u4e0d\u5141\u8bb8\u6bd4\u8f83\n - \u4f46\u662fChoiceEnum\u662f\u76f4\u63a5\u53d6\u503c\uff0c\u53ef\u4ee5\u7528\u6765\u505a\u6bd4\u8f83\u8fd0\u7b97\n - \u679a\u4e3e\u7c7b\u5b9a\u4e49\u65f6\uff0c\u65e0\u6cd5\u8bc6\u522b\u591a\u4e2a\u76f8\u540c\u7684Key\n - \u5728\u591a\u7ee7\u627f\u65b9\u9762\u4f1a\u53d7\u9650\n- `Enum`\u548cPython3\u539f\u751fenum.py\u5bf9\u6bd4\uff0c\u4fdd\u7559\u4e86`Enum`\u7c7b\u548c`unique`\u65b9\u6cd5\n- `ChoiceEnum`\u548cDjango\u7684 models.Choices \u7684\u4f18\u52bf\u5728\u4e8e\u4f4e\u7248\u672cDjango\u4e5f\u80fd\u4f7f\u7528\uff0c\u4e14\u666e\u901aPython\u9879\u76ee\u811a\u672c\u4e5f\u80fd\u4f7f\u7528\n- \u65b0\u589e\u4e86\u989d\u5916\u7684\u7279\u6027\n - \u989d\u5916\u591a\u51fa\u4e86`ChoiceEnum.extra`\u7684\u7528\u6cd5\uff0c\u5bf9\u4e0d\u540c\u679a\u4e3e\u6210\u5458\u505a\u6620\u5c04\u914d\u7f6e\u76f8\u5173\u573a\u666f\u53ef\u4ee5\u4f7f\u7528\n - \u589e\u52a0\u65b9\u6cd5`ChoiceEnum.to_js_enum`\u8fd4\u56de\u6570\u7ec4\u6570\u636e\uff0c\u53ef\u4ee5\u7528\u4e8e\u524d\u7aef\u679a\u4e3e\u5e93 [js-enumerate](https://github.com/SkylerHu/js-enum) \u521d\u59cb\u5316\u4f7f\u7528",
"bugtrack_url": null,
"license": "MIT Licence",
"summary": "enums for choices fields",
"version": "1.1.1",
"project_urls": {
"Homepage": "https://github.com/SkylerHu/py-enum.git"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "45cc79712e9b5e70ed4dcf0773f3a40ff7d40df1e0d3cf3f81042b6ade06fbc7",
"md5": "fe45e63c38c660a30eadb6304ea72d80",
"sha256": "56dc4430eee495a96b671ec975898de3c98a72636b683583e8d88e8b0bf270f6"
},
"downloads": -1,
"filename": "py-enum-1.1.1.tar.gz",
"has_sig": false,
"md5_digest": "fe45e63c38c660a30eadb6304ea72d80",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=2.7",
"size": 30670,
"upload_time": "2024-05-03T16:31:42",
"upload_time_iso_8601": "2024-05-03T16:31:42.988127Z",
"url": "https://files.pythonhosted.org/packages/45/cc/79712e9b5e70ed4dcf0773f3a40ff7d40df1e0d3cf3f81042b6ade06fbc7/py-enum-1.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-05-03 16:31:42",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "SkylerHu",
"github_project": "py-enum",
"travis_ci": false,
"coveralls": true,
"github_actions": false,
"tox": true,
"lcname": "py-enum"
}