python迭代
迭代:重复做一件事
iterable(可迭代)对象
支持每次返回自己所包含的一个成员的对象
对象实现了__iter__方法
序列类型, 如: list,str,tuple
非序列类型, 如:dict,file
用户自定义的一些包含了__iter__或__getitem__()方法的类
迭代器(iterator)又称游标(cursor),它是程序设计的软件设计模式,是一种可在容器物件(container,如列表等)上实现元素遍历的接口
迭代器是一种特殊的数据结构,当然在Python中,它也是以对象的形式存在的
简单理解方式:对于一个集体中的每一个元素,想要执行遍历,那么针对这个集体的迭代器定义了遍历集体中每一个元素的顺序或者方法
在Python中,迭代器是遵循迭代协议的对象
使用iter()可从任何序列对象中得到迭代器
若要实现迭代器,需要在类中定义next()方法(Python 3中是__next__())
要使得迭代器指向下一个元素,则使用成员函数next()
在Python中,是函数next(),而非成员函数
当没有元素时,则引发StopIteration异常
for 循环可用于任何可迭代对象
for循环开始时,会通过迭代协议传递给iter()内置函数,从而能够从可迭代对象中获得一个迭代器,返回的对象含有需要的next方法
python列表解析
列表解析是python迭代机制的一种应用,它常用于实现创建新的列表,因此要放置于[]中
语法:
[expression for iter_var in iterable]
[expression for iter_var in iterable if cond_expr]
l = [x**2 for x in range(9)]
l
[0,1,4,9,16,25,36,49,64]
列表解析:根据已有列表快速生成新列表
求1-10所有整数的平方除以2的结果
代码如下:
for i in [i**2 for i in range(1,11)]:
print i/2,
l1 = ['x','y','z'] l2 = [1,2,3]
l3 = [(i,j) for i in l1 for j in l2]
生成器表达式
生成器表达式并不真正创建数字列表,而是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目"产生"(yield)出来
生成器表达式使用了"惰性计算"或称作"延迟求值"的机制
序列过长,并且每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析
生成器表达式于python 2.4引入
语法
(expr for iter_var in iterable)
(expr for iter_var in iterable if cond_expr)
for j in (i**2 for i in range(1,11)): print j/2
生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用yield语句。每次next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)。以下示例演示了生成器可以很简单的创建出来:
def reverse(data):
for index in range(len(data)-1,-1,-1):
yield data[index]
for char in reverse('hello'):
print(char),
运行结果:
o l l e h
关于迭代器和生成器的区别,生成器能做到迭代器能做的所有事,而且因为自动创建了__iter__()和 next()方法,生成器显得特别简洁,而且生成器也是高效的。
除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出StopIteration异常。一个带有yield的函数就是一个 生成器,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用next()(在 for 循环中会自动调用next())才开始执行。
虽然执行流程仍按函数的流程执行,但每执行到一个yield语句就会中断,并返回一个迭代值,下次执行时从yield的下一个语句继续执行。
看起来就好像一个函数在正常执行的过程中被yield中断了数次,每次中断都会通过yield返回当前的迭代值(yield暂停一个函数,next()从其暂停处恢复其运行)。
另外对于生成器,python还提供了一个生成器表达式:类似与一个yield值的匿名函数。表达式本身看起来像列表推到, 但不是用方括号而是用圆括号包围起来:
s = {'E', 'D', 'M', 'O', 'N', 'S', 'R', 'Y'}
g = (ord(c) for c in s) //生成器
g
<generator object <genexpr> at 0x7f00535c11e0>
for i in g:
print (i),
运行结果:69 68 77 79 78 83 82 89
s = {'E', 'D', 'M', 'O', 'N', 'S', 'R', 'Y'}
g = [ord(c) for c in s] //列表解析
g
运行结果:[69, 68, 77, 79, 78, 83, 82, 89]
如果需要,可以将生成器表达式传给tuple、list或是set来迭代所有的值并且返回元组、列表或是集合。
在这种情况下,不需要一对额外的括号直接将生成器表达式 ord(c) for c in unique_characters传给tuple()等函数就可以了, Python 会推断出它是一个生成器表达式。
使用生成器是因为效率。使用生成器表达式取代列表解析可以同时节省 cpu 和 内存(ram)。
如果你构造一个列表的目的仅仅是传递给别的函数,(比如 传递给tuple()或者set()), 那就用生成器表达式替代吧!
产生偏移和元素
enumerate
range可在非完备遍历中用于生成索引偏移,而非偏移处的元素
如果同时需要偏移索引和偏移元素,则可以使用enumerate()函数
此内置函数返回一个生成器对象
S = ‘hello world’
E = enumerate(S)
E.next()
(0,’h’)
E.next()
(1,’e’)
url = 'www.magedu.com'
g1 = enumerate(url)
g1.next()