1.迭代器
引文
在Python的技术类面试中,迭代器、生成器与装饰器相关的话题通常是必问的;
熟练掌握具体的知识也有助于我们写出好更优雅的代码;
这里参考相关的资料详细地学习下,备以后查阅。
本文是迭代器,生成器和装饰器系列的第一篇文章,主要讲解迭代器;
探索迭代器
什么是迭代器?标准定义是什么?——直接讲定义不会太深刻,那我们就一步一步地引出迭代器;
首先,众所周知Python支持两种循环结构,while和for...in;
# while loop
while expression:
statement
# for loop
for i in s:
statement
while循环结构中,只要expression为逻辑真,就会循环执行statement中的逻辑;
直到expression最终变为逻辑假,循环才会终止;
而在for循环中,循环会遍历完所有的s中的元素,才会停止循环;
而s的类型,通常为Python中的“容器类型”和支持“迭代协议”的类型。
所谓的“容器类型”包括常用的内建类型:list,tuple,str;"迭代协议"具体指什么我们稍后再说;
对于支持迭代协议的类型,官方的迭代实现:
PyObject *iterator = PyObject_GetIter(obj); // 声明一个指向迭代器的指针
PyObject *item; // 声明一个元素指针
if (iterator == NULL) { // 校验
/* propagate error */
}
while (item = PyIter_Next(iterator)) { // 获取下一个元素
/* do something with item */
...
/* release reference when done */ // 释放掉item指向的空间
Py_DECREF(item);
}
Py_DECREF(iterator); // 释放掉iterator指向的迭代器对象
if (PyErr_Occurred()) {
/* propagate error */
}
else {
/* continue doing useful work */
}
用Python实现是这样的:
it = s.__iter__() # s支持迭代协议,获取一个迭代器
while 1:
try:
i = it.next() # 尝试取下一个元素,不存在就抛出StopIteration (use __next__() in py3)
except StopIteration: # 捕获异常
break
# Perform operation on i
从上述代码来看,对于一个所谓的支持"迭代协议"的对象,
若要实现对for循环的支持,__iter__和next()(在py3中是__next__())方法是关键;
由这两个方法组成了"迭代协议",支持迭代协议的类型就可以满足for...in...结构的使用条件;
所以,支持“迭代协议”的对象就可以称为迭代对象;具体来说就是这两个方法;
iterator.__iter__(),要求返回一个迭代对象;iterator.next()(iterator.__next__()in py3),要求返回下一个元素,若没有的话就抛出StopIteration异常;
容器类对象的的for循环其实依赖于一个container.__iter__()方法,
此方法要求返回一个“迭代器对象”,这个返回的迭代对象实现了“迭代协议”;
在官方的for迭代实现中,容器类型依赖于__iter__()返回一个迭代器对象来完成迭代;
可以通过自定义__iter__和next()(__next__())方法来自定义迭代器;
class Demo(object):
def __init__(self):
self._list = [1, 2, 3, 4]
self._count = 0
def __iter__(self):
return self
def next(self):
if self._count > len(self._list) - 1:
raise StopIteration()
r = self._list[self._count]
self._count += 1
return r
if __name__ == '__main__':
demo = Demo()
for i in demo:
print i
itertools标准库
标准库itertools提供了更多对各种迭代器的支持,包括无限循环,序列全排列,以及对迭代器操作等支持;
如:
# 无限循环迭代器
itertools.count(start, [step]) # count(10) => 10, 11, 12, ... 无限循环
itertools.cycle(p) # cycle('ABCD') => A B C D A B C D A B C D ...
itertools.repeat(elem, [n]) # repeat(10, 3) => 10, 10, 10
# 根据最短序列中止
itertools.accumulate(p, [func]) # !py3 accumulate([1, 2, 3, 4, 5]) => 1, 3, 6, 10, 15
itertools.chain(p, q, ...) # chain('ABC', 'DEF') => A B C D E F
itertools.chain.from_iterable(iterable) # chain.from_iterable(['ABC', 'DEF']) => A B C D E F
itertools.compress(data, selectors) # compress('ABCDEF', [1, 0, 1, 0, 1, 1]) => A C E F
...
itertools.product(*iterables, repeat=1)
# 输出输入的笛卡尔积
# product('ABCD', 'xy') => Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) => 000 001 010 011 100 101 110 111
itertools.permutations(p, r=None)
# 长度为r的所有可能的p的子序列, r为None时默认获取最大长度全排列
# permutations('ABCD', 2) => AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) => 012 021 102 120 201 210
...
参考资料:
- pydoc中 迭代器类型 https://docs.python.org/2/library/stdtypes.html#iterator-types
- Python Essential Reference, 4th edition, chap 5, Loops and Iteration
- itertools标准库 https://docs.python.org/2/library/itertools.html
浙公网安备 33010602011771号