1、迭代器
迭代器是访问集合元素的一种方式,迭代器对象从集合的第一个元素开始,直到所有的元素访问完成后结束,
迭代器主要是用来和for循环进行配合,从而能用一种简单访问的接口来访问集合的元素,也是一种比较有性能的方法,因为在使用迭代器的时候,每次只返回一个元素,不像列表,每次需要在内存中加载所有的元素。
可迭代的对象有序列类型string,list,tuple,非序列类型dict,file,还有就是自定义类型,当使用自定义类型的时候,必须实现__iter__()或者__getitem__()方法。
迭代器是必须实现了__iter__()方法和next()方法,__iter__()方法返回迭代器自身,next()方法集合的下一个元素。
迭代器一定是可迭代的,而可迭代的对象并不一定是迭代器,当将可迭代对象转换成迭代器的时候,可以使用iter()工厂函数,如下:
>>> myTuple = (123,'xyz',34.2) (list是可迭代对象,内部实现了__iter__()方法)
>>> i = iter(myTuple)(将可迭代对象转换成迭代器,使用iter工厂函数)
>>> type(i)(i是一个迭代器对象)
<type 'tupleiterator'>
>>> i.next() (迭代器具有next方法,返回下一个元素的值)
123
>>> i.next()
'xyz'
>>> i.next()
34.2
>>> i.next()(当所有元素都返回了时,会引发StopIteration异常)
Traceback (most recent call last):
File"<stdin>", line 1, in <module>
StopIteration
>>> k = myTuple.__iter__()(也可以调用__iter__()函数返回一个迭代器)
>>> type(k)
<type 'tupleiterator'>
迭代器的限制,当使用迭代器的时候,不能向后移动,也不能回到开始,也不能复制一个迭代器,当要迭代同一个对象的时候,必须重新创建一个迭代器。
在使用for循环的时候,会自动的将对象转换成一个迭代器,然后每次返回一个值,并且for能自动的捕捉到异常,然后退出循环。
>>> for i in myTuple:(使用for来迭代某个可迭代的对象)
... print i
...
123
xyz
34.2
>>> iterTuple=iter(myTuple) (for循环会得到一个迭代器对象)
>>> while True: (进行循环,使用迭代器的next方法得到下一个值,并且自动捕捉异常,然后退出)
... try:
... iterTuple.next()
... exceptStopIteration:
... break
...
123
'xyz'
34.2
>>>myDict={"name":"kel","age":28,"sex":"man"}(遍历字典的时候,默认是遍历字典的keys返回一个列表,然后返回一个迭代器)
>>> for i in myDict:
... print i
...
age
name
sex
>>> myDict.keys().__iter__()(字典类型的迭代器)
<listiterator object at 0x7f535d589c90>
>>> type(i)
<type 'dictionary-keyiterator'>
>>> k=myDict.iterkeys()(字典键的迭代器)
>>> type(k)
<type 'dictionary-keyiterator'>
>>> k=myDict.itervalues()(字典值的迭代器)
>>> type(k)
<type 'dictionary-valueiterator'>
>>> k=myDict.iteritems()(字典项的迭代器)
>>> type(k)
<type 'dictionary-itemiterator'>
>>> f=file('kel.log')(使用for循环读取文件的时候,默认是调用文件的readlines方法返回一个列表,然后返回一个迭代器)
>>> for i in f:
... printi.strip()
...
some
file
>>> i = f.__iter__()
>>> type(i)
<type 'file'>
>>> type(f)
<type 'file'>
>>> k=f.readlines().__iter__()(文件类型的迭代器)
>>> type(k)
<type 'listiterator'>
2、列表解析
列表解析主要是用来动态的生成一个新的列表,如下所示语法:
>>> l1 = [1,2,3,4]
>>> for i in l1:(使用for循环来求列表l1偶数的平方)
... if i%2 ==0:
... l2.append(i**2)
...
>>> l2
[4, 16]
>>> l2 = [i*2 for i in l1 if i%2 == 0](求列表l1偶数的平方)
>>> l2
[4, 8]
可以看出,当使用列表解析的时候,简单明了,再例如如下的例子:
>>> f = file('kel.log')(统计文件中单词的个数)
>>> count =0
>>> for eachline in f:(使用双重循环来计算单词的个数)
... for wordin eachline.strip().split():
... count +=1
...
>>> count
4
>>> f.seek(0)
>>> len([word for line in f for word inline.strip().split()])(使用列表解析来计算单词的个数)
4
>>> sum([len(word) for line in f for word inline.strip().split()])(使用列表解析统计字母的个数)
16
列表解析支持嵌套的for循环。列表解析的不足就是一次性生成大量的数据,全部放入到内存中,那么可能对大量数据的迭代产生影响。
3、生成器表达式
生成器表达式是列表解析的一个扩展,生成器表达式和列表解析的语法基本相同,但是不同的是,生成器表达式返回的是一个生成器对象,而列表解析返回的是一个列表对象,如下所示:
>>> alist = [1,2,3,4]
>>> [a**2 for a in alist] (列表解析返回一个新的列表)
[1, 4, 9, 16]
>>> (a**2 for a in alist)(生成器表达式返回一个生成器对象)
<generator object <genexpr> at0x7fa2beac0c80>
生成器每次只产生一个数据,从而在使用内存上占有更大的优势,生成器产生的值是yield出来的,使用了延迟计算的方式,也就是在需要的时候才会返回这个值。
>>> f = open('kel.log')
>>> sum(len(word) for line in f for word inline.strip().split())(使用生成器表达式,节省内存)
16
>>> f.close()
>>> max(len(line.strip()) for line inopen('/var/log/messages') )(使用生成器表达式一行代码统计最长的行长度)