- 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章 性能剖析与优化
建议63:熟悉 Python 对象协议
因为Python是一门动态语言,Duck Typing的概念遍布其中,所以其中的Concept并不以类型的约束为载体,而另外使用称为协议的概念。所谓协议,类似你讲英语,我也讲英语,我们就可以交流;在Python中就是我需要调用你某个方法,你正好就有这个方法。比如在字符串格式化中,如果有占位符%s,那么按照字符串转换的协议,Python会去自动地调用相应对象的__str__()方法。
>>> class Object(object): ... def __str__(self): ... print 'called __str__' ... return super(Object, self).__str__() ... >>> o = Object() >>> print "%s" % o called __str__ <__main__.Object object at 0x10277a5d0>
这倒数第二行就是明证。除了__str__()外,还有其他的方法,比如__repr__()、__int__()、__long__()、__float__()、__nonzero__()等,统称类型转换协议。除了类型转换协议之外,还有许多其他协议。
1)用以比较大小的协议,这个协议依赖于__cmp__()方法,与C语言库函数cmp类似,当两者相等时,返回0,当self<other时返回负值,反之返回正值。因为它的这种复杂性,所以Python又有__eq__()、__ne__()、__lt__()、__gt__()等方法来实现相等、不等、小于和大于的判定。这也就是Python对==、!=、<和>等操作符的进行重载的支撑机制。
2)数值类型相关的协议,这一类的函数比较多,如表6-2所示。
表6-2 Python的协议与函数对应关系表
基本上,只要实现了表6-2中的几个方法,基本上就能够模拟数值类型了。不过还需要提到一个Python中特有的概念:反运算。别被吓着,其实非常简单。以加法为例,something+other,调用的是something的__add__()方法,如果something没有__add__()方法怎么办呢?调用other.__add__()是不对的,这时候Python有一个反运算的协议,它会去查看other有没有__radd__()方法,如果有,则以something为参数调用之。类似__radd__()的方法,所有的数值运算符和位运算符都是支持的,规则也是一律在前面加上前缀r即可,在此不再细表。
3)容器类型协议。容器的协议是非常浅显的,既然为容器,那么必然要有协议查询内含多少对象,在Python中,就是要支持内置函数len(),通过__len__()来完成,一目了然。而__getitem__()、__setitem__()、__delitem__()则对应读、写和删除,也很好理解。__iter__()实现了迭代器协议,而__reversed__()则提供对内置函数reversed()的支持。容器类型中最有特色的是对成员关系的判断符in和not in的支持,这个方法叫__contains__(),只要支持这个函数就能够使用in和not in运算符了。
4)可调用对象协议。所谓可调用对象,即类似函数对象,能够让类实例表现得像函数一样,这样就可以让每一个函数调用都有所不同。
>>> class Functor(object): ... def __init__(self, context): ... self._context = context ... def __call__(self): ... print 'do something with %s' % self._context ... >>> lai_functor = Functor('lai') >>> yong_functor = Functor('yong') >>> lai_functor() do something with lai >>> yong_functor() do something with yong
5)与可调用对象差不多的,还有一个可哈希对象,它是通过__hash__()方法来支持hash()这个内置函数的,这在创建自己的类型时非常有用,因为只有支持可哈希协议的类型才能作为dict的键类型(不过只要继承自object的新式类默认就支持了)。
6)前面的文档谈对描述符协议和属性交互协议(__getattr__()、__setattr__()、__delattr()),那么剩下来还值得一谈的就是上下文管理器协议了,也就是对with语句的支持,这个协议通过__enter__()和__exit__()两个方法来实现对资源的清理,确保资源无论在什么情况下都会正常清理。
class Closer: ''' 通过with 语句和一个close 方法来关闭一个对象''' def __init__(self, obj): self.obj = obj def __enter__(self): return self.obj # bound to target def __exit__(self, exception_type, exception_val, trace): try: self.obj.close() except AttributeError: # obj isn't closable print 'Not closable.' return True # exception handled successfully
对于实现了这两个方法的Closer类,我们可以如下使用它:
>>> from ftplib import FTP >>> with Closer(FTP('ftp.somesite.com')) as conn: ... conn.dir() ... >>> conn.dir() >>>
可以看到第二次调用conn.dir()已经没有输出,这是因为这个FTP连接会话已被关闭的缘故。与这里Closer类似的类在标准库中已经存在,就是contextlib里的closing。
至此,常用的对象协议就讲完了,只要活学活用这些协议,就能够写出更为Pythonic的代码。不过也要注意,协议不像C++、Java等语言中的接口,它更像是声明,没有语言上的约束力,需要大家共同遵守。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论