Python:迭代器
在使用Python的过程中,很容易混淆如下几个关联的概念:
- 容器(container)
- 可迭代对象(Iterable)
- 迭代器(Iterator)
- 生成器(generator)
- 生成器表达式
- {list, set, dict} 解析式
1.容器(container)
容器是用来储存元素的一种数据结构,它支持隶属测试,容器将所有数据保存在内存中,在Python中典型的容器有:
- list, deque, ...
- set,frozesets,...
- dict, defaultdict, OrderedDict, Counter, ...
- tuple, namedtuple, ...
- str
通过判断一个对象是否包含某个元素来确定它是否为一个容器
>>> assert 1 in [1,2,3] # lists >>> assert 4 not in [1,2,3] >>> assert 1 in {1,2,3} # sets >>> assert 4 not in {1,2,3} >>> assert 1 in (12,3) # tuples >>> assert 4 not in (1,2,3)
字典容器通过检查是否包含某个键来进行判断
>>> d = {1:"foo", 2:"bar", 3:"qux"} >>> assert 1 in d >>> assert 4 in d Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError >>> assert "foo" in d Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError
字符串通过检查是否包含某个子 串来判断
>>> s="foo" >>> assert "f" in s >>> assert "b" in s Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError
2.可迭代对象
如果给定一个list或tuple,我们可以通过for
循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等。但凡是可以返回一个 迭代器 的对象都可称之为可迭代对象,听起来可能有点困惑,没关系,可迭代对象与迭代器有一个非常重要的区别。
>>> x=[1,2,3] >>> y=iter(x) >>> z=iter(x) >>> next(y) 1 >>> next(y) 2 >>> next(z) 1 >>> type(x) <class 'list'> >>> type(y) <class 'list_iterator'>
x 是一个可迭代对象,可迭代对象和容器一样是一种通俗的叫法,并不是指某种具体的数据类型,list是可迭代对象,dict是可迭代对象,set也是可迭代对象。 y 和 z 是两个独立的迭代器,迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。迭代器有一种具体的迭代器类型,比如 list_iterator , set_iterator 。可迭代对象实现了 __iter__ 和 __next__ 方法(python2中是 next 方法,python3是 __next__ 方法),这两个方法对应内置函数 iter() 和 next() 。 __iter__ 方法返回可迭代对象本身,这使得他既是一个可迭代对象同时也是一个迭代器。
3.一些迭代工具
3.1并行迭代
>>> names=['greg','greg1','greg2'] >>> ages=[18,12,13] >>> for i in range(len(names)): print(names[i]+' is '+str(ages[i])) greg2 is 13 greg2 is 13 greg2 is 13 >>> for n,a in zip(names,ages): print(names[i]+' is '+str(ages[i])) greg2 is 13 greg2 is 13 greg2 is 13
3.2 编号迭代
list1 = ["这", "是", "一个", "测试"] for index, item in enumerate(list1): print(index, item) 0 这 1 是 2 一个 3 测试
3.2 翻转和排序迭代
>>> sorted([2,6,3,1,5]) [1, 2, 3, 5, 6] >>> sorted('Hello,world!') ['!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w'] >>> list(reversed('Hello,world!')) ['!', 'd', 'l', 'r', 'o', 'w', ',', 'o', 'l', 'l', 'e', 'H'] >>> ''.join(reversed('Hello,world!')) '!dlrow,olleH'
4.迭代器(iterator)
它是一个带状态的对象,他能在你调用 next() 方法的时候返回容器中的下一个值,任何实现了 __next__() (python2中实现 next() )方法的对象都是迭代器,至于它是如何实现的这并不重要。
#迭代器,1,有iter方法。2,有next方法 # 可以使用isinstance()判断一个对象是否是Iterable对象: l=[1,2,3,4] d=iter(l) print(d) #<list_iterator object at 0x000002C34B71C160> # list,tuple,dict,string:iterable print(next(d)) print(next(d)) print(next(d)) print(next(d)) # for循环内部三件事:1,调用可迭代对象iter方法,返回迭代器对象 # 2,不断调用迭代器对象的next方法 # 3,处理StopIteration,遇到退出 # for i in [1,2,3,4]: # iter([1,2,3,4]) from collections import Iterator,Iterable print(isinstance(2,list))#False l=[1,2,3,4] d=iter(l) print(d) print(isinstance(l,list)) print(isinstance(l,Iterable)) print(isinstance({}, Iterable)) print(isinstance('abc', Iterable)) print(isinstance((x for x in range(10)), Iterable)) print(isinstance(100, Iterable))#False # 小结 # 凡是可作用于for循环的对象都是Iterable类型; # 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列; # 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。 # Python的for循环本质上就是通过不断调用next()函数实现的,例如: # 首先获得Iterator对象: it = iter([1, 2, 3, 4, 5]) while True:# 循环: try:# 获得下一个值: x = next(it) except StopIteration:# 遇到StopIteration就退出循环 break
可以使用迭代器来解决复用可占空间的问题
class Fab(object): def __init__(self, max): self.max = max self.n, self.a, self.b = 0, 0, 1 def __iter__(self): return self def __next__(self): if self.n < self.max: r = self.b self.a, self.b = self.b, self.a + self.b self.n = self.n + 1 return r raise StopIteration() for key in Fab(5): print(key) # 1 # 1 # 2 # 3 # 5
Fab既是一个可迭代对象(因为它实现了 __iter__ 方法),又是一个迭代器(因为实现了 __next__ 方法)。实例变量 self .a 和 self.b 用户维护迭代器内部的状态。每次调用 next() 方法的时候做两件事:
- 为下一次调用 next() 方法修改状态
- 为当前这次调用生成返回结果
迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。
5.从迭代器得到序列
list构造方法显式将迭代器转化为列表
class TestIterator: value=0 def __next__(self): self.value +=1 if self.value>10: raise StopIteration return self.value def __iter__(self): return self ti=TestIterator() print(list(ti)) #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]