- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议11:理解枚举替代实现的缺陷
关于枚举最经典的例子大概非季节和星期莫属了,它能够以更接近自然语言的方式来表达数据,使得程序的可读性和可维护性大大提高。然而,很不幸,也许你习惯了其他语言中的枚举类型,但在Python3.4以前却并不提供。关于要不要加入枚举类型的问题就引起了不少讨论,在PEP354中曾提出增加枚举的建议,但被拒绝。于是人们充分利用Python的动态性这个特征,想出了枚举的各种替代实现方式。
1)使用类属性。
>>> class Seasons: ... Spring = 0 ... Summer = 1 ... Autumn = 2 ... Winter = 3 ... >>> print Seasons.Spring
上面的例子可以直接简化为:
>>> class Seasons: ... Spring,Summer,Autumn,Winter=range(4) ...
2)借助函数。
>>> def enum(*posarg, **keysarg): ... return type("Enum", (object,), dict(zip(posarg, xrange(len(posarg))), ** keysarg)) ... >>> Seasons = enum("Spring","Summer","Autumn",Winter=1) >>> Seasons.Spring 0
3)使用collections.namedtuple。
>>> Seasons = namedtuple('Seasons','Spring Summer Autumn Winter')._make(range(4)) >>> print Seasons.Spring 0
Python中枚举的替代实现方式远不止上述这些,在此就不一一列举了。那么,既然枚举在Python中有替代的实现方式,为什么人们还要执着地提出各自建议要求语言实现枚举呢?显然,这些替代实现有其不合理的地方。
允许枚举值重复。我们以collections.namedtuple为例,下面的例子中枚举值Spring与Autumn相等,但却不会提示任何错误。
>>> Seasons._replace(Spring =2) Seasons(Spring=2, Summter=1, Autumn=2, Winter=3) #Spring 和Autumn 的值相等,都为2
支持无意义的操作。
>>> Seasons.Summer+Seasons.Autumn == Seasons.Winter True #Seasons.Summer+Seasons.Autumn 相加无任何实际意义
实际上Python2.7以后的版本还有另外一种替代选择——使用第三方模块flufl.enum,它包含两种枚举类:一种是Enum,只要保证枚举值唯一即可,对值的类型没限制;还有一种是IntEnum,其枚举值为int型。
>>> from flufl.enum import Enum >>> class Seasons(Enum): # 继承自Enum 定义枚举 ... Spring ="Spring" ... Summer = 2 ... Autumn = 3 ... Winter = 4 ... >>> Seasons = Enum('Seasons', 'Spring Sumter Autumn Winter')
flufl.enum提供了__members__属性,可以对枚举名称进行迭代。
>>> for member in Seasons.__members__: ... print member ... Spring Summer Autumn Winter
可以直接使用value属性获取枚举元素的值,如:
>>> print Seasons.Summer.value 2
flufl.enum不支持枚举元素的比较。
>>> Seasons.Summer <Seasons.Autumn #flufl.enum 不支持无意义的操作 Traceback (most recent call last): ... ... raise NotImplementedError NotImplementedError
更多关于flufl.enum的使用可以参考网页http://Pythonhosted.org/flufl.enum/docs/using.html的内容。
值得一提的是,Python3.4中根据PEP435的建议终于加入了枚举Enum,其实现主要参考实现flufl.enum,但两者之间还是存在一些差别,如flufl.enum允许枚举继承,而Enum仅在父类没有任何枚举成员的时候才允许继承等,读者可以仔细阅读PEP435了解更多详情。另外,如果要在Python3.4之前的版本中使用枚举Enum,可以安装Enum的向后兼容包enum34,下载地址为https://pypi.Python.org/pypi/enum34。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论