改善Python程序-Python对象协议

熟悉Python对象协议

在字符串格式化中,如果有占位符%s,那么按照字符串转换的协议,Python会去自动地调用相应对象的str()方法。比如 repr(),int(),long(),float_(),nonzero__() 等统称类型转换协议。

1
2
3
4
5
6
7
8
>>> 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 0xl0277a5d0>

(1)用以比较大小的协议:依赖于cmp()方法,与C语言库函数cmp类似,当两者相等时,返回0,当sdf < other时返回负值,反之返回正值。因为它的这种复杂性,所 以Python又有 eq()、ne()、lt()、gt() 等方法来实现相等、不等、小于和大于 的判定。这也就是Python对=、!=、<和> 等操作符的进行重载的支撑机制。

(2)数值类型相关的协议
| 方 法 | 操作符/函数 | 说 明 |
|—————|————-|————————————————————|
| add | + | 加 |
| sub | - | 减 |
| mul | | 乘 |
| div | / | 除 |
| floordiv | // | 整除 |
| truediv | / | 真除法,当future.division起作用时调用,否则调用div |
| pow | ** | 幂运算 |
| mod | % | 取余 |
| divmod | divmod() | 余、除 |
| lshift | << | 向左移位 |
| rshift | >> | 向右移位 |
| and | & | 与 |
| or | | | 或 |
| xor | ^ | 异或 |
| invert | ~ | 非 |
| iadd | += | |
| isub | -= | |
| imul |
= | |
| idiv | /= | |
| ifloordiv | //= | |
| itruediv | /= | |
| ipow | **= | |
| imod | %= | |
| ilshift | <<= | |
| irshift | >>= | |
| iand | &= | |
| ior | |= | |
| ixor | ^= | |
| pos | + | 正 |
| neg | - | 负 |
| abs | abs() | 绝对值 |

基本上就能够模拟数值类型了。还需要提到一个Python中特有的概念:反运算。以加法为例,something+other调用的是something 的add()方法,如果something没有add()方法?调用other.add()是不对的,这时候Python有一个反运算的协议,它会去査看other有没有radd()方法,如果有,则以something为参数调用之

(3)容器类型协议: 就是要支持内置函数len(),通过len()来完成,而 getitem()、setitem()、delitem() 则对应读、写和删除。iter() 实现了迭代器协议,而 reversed() 则提供对函数 reversed() 的支持。容器类型中最有特色的是对成员关系的判断符in和not in的支持,这个方法叫contains(),只要支持这个函数就能够使用in和not in运算符

(4)可调用对象协议:所谓可调用对象,即类似函数对象,能够让类实例表现得像函数一样,这样就可以让每一个函数调用都有所不同。

1
2
3
4
5
6
7
8
9
10
11
>>> 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)上下文管理器协议

1
2
3
4
5
6
7
8
9
10
11
12
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

熟悉Python的迭代器协议

iter() 可以输入两个实参,只介绍一个参数的形式。iter() 函数返回一个迭代器对象,接受的参数是一个实现了 iter() 方法的容器或迭代器。对于容器而言,iter() 方法返回一个迭代器对象,而对迭代器而言,它的iter()方法返回其自身。

1
2
3
>>> it = iter (alist)
>>> it2 = iter (it)
>>> assert id (it) == id (it2)

协议简单归纳如下:
(1)实现iter()方法,返回一个迭代器
(2)实现next()方法,返回当前的元素,并指向下一个元素的位置,如果当前位置已无元素,则抛出Stoplteration异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 打印斐波那契数列的前10项
class Fib(object):
def __init__(self):
self._a = 0
self._b = 1
def __iter__(self):
return self
def next (self):
self._a, self._b = self._b, self._a + self._b
return self.a
for i, f in enumerate(Fib()):
print f
if i > 10:
break

itertools函数库

(1)zip、map、filter、slice的替代,izip(izip_ longest)、imap(startmap)、ifilter(ifilterfalse)、islice,与原来的那几个内置函数有一样的功能,只是返冋的是迭代器
(2)chain()用以同时连续地迭代多个序列;compress()、dropwhile()和takewhile()能用以遴选序列元素;tee()对序列作n次迭代,

1
2
[k for k, g in groupby('AAAABBBCCDAABBB')] —> A B C D A B
[list(g) for k, g in groupby('AAAABBBCCD')] —> AAAA BBB CC D

(3)cmmt()、cycle()、repeat()等函数分别可以产生算术递增数列、无限重复实参序列的序列和重复产生同一个值的序列,product()计算m个序列的n次笛卡尔积,permutations()产生全排列,combinations()产生无重复元素的组合,combinations_with_replacemenl()产生有重复元素的组合