1.迭代器

引文


Python的技术类面试中,迭代器、生成器与装饰器相关的话题通常是必问的;
熟练掌握具体的知识也有助于我们写出好更优雅的代码;
这里参考相关的资料详细地学习下,备以后查阅。

本文是迭代器,生成器和装饰器系列的第一篇文章,主要讲解迭代器;

探索迭代器


什么是迭代器?标准定义是什么?——直接讲定义不会太深刻,那我们就一步一步地引出迭代器;

首先,众所周知Python支持两种循环结构,whilefor...in

# while loop
while expression:
	statement
	
# for loop
for i in s:
	statement

while循环结构中,只要expression为逻辑真,就会循环执行statement中的逻辑;
直到expression最终变为逻辑假,循环才会终止;

而在for循环中,循环会遍历完所有的s中的元素,才会停止循环;
s的类型,通常为Python中的“容器类型”和支持“迭代协议”的类型。

所谓的“容器类型”包括常用的内建类型:listtuplestr;"迭代协议"具体指什么我们稍后再说;

对于支持迭代协议的类型,官方的迭代实现:

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...结构的使用条件;

所以,支持“迭代协议”的对象就可以称为迭代对象;具体来说就是这两个方法;

  1. iterator.__iter__(),要求返回一个迭代对象;
  2. 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
	
	...

参考资料:


  1. pydoc中 迭代器类型 https://docs.python.org/2/library/stdtypes.html#iterator-types
  2. Python Essential Reference, 4th edition, chap 5, Loops and Iteration
  3. itertools标准库 https://docs.python.org/2/library/itertools.html

posted on 2017-06-01 00:17  yabzhang  阅读(151)  评论(0)    收藏  举报

导航