一、可迭代对象
1.迭代的概念
通过for循环遍历取值的过程叫做迭代。
2.可迭代对象
能够通过for循环遍历取值的对象叫做可迭代对象,比如字符串、列表、元组、字典、集合、range都属于可迭代对象。
可以通过isinstance函数来判断对象是否为可迭代对象:
fromcollections.abcimportIterableprint(isinstance([], Iterable)) # Trueprint(isinstance("", Iterable)) # Trueprint(isinstance({}, Iterable)) # Trueprint(isinstance((), Iterable)) # Trueprint(isinstance({"name": "lucy"}, Iterable)) # True
二、迭代器
1.迭代器的概念
- 迭代器是一个可以记住遍历的位置的对象
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只能往前不会后退
迭代器有两个基本的方法:iter() 和 next(),字符串,列表或元组对象都可用于创建迭代器,迭代器对象可以使用常规 for 语句进行遍历,也可以使用 next() 函数来遍历。list、tuple等都是可迭代对象,可以通过iter()函数获取这些可迭代对象的迭代器。然后我们可以对获取到的迭代器不断使用next()函数来获取下一条数据。iter()函数实际上就是调用了可迭代对象的 __iter__ 方法。next()实际调用了 __next__()方法。
iter() ----- __iter__()
next() ----- __next__()
2.用iter()创建迭代器
将字符串转换为迭代器:
name="james"new_name=iter(name) print(type(name)) # <class 'str'>print(type(new_name)) # <class 'str_iterator'>print(isinstance(new_name, Iterator)) # True
将列表转换为迭代器:
list1= [1, 2, 3, 4, 5] new_list1=iter(list1) print(type(list1)) # <class 'list'>print(type(new_list1)) # <class 'list_iterator'>print(isinstance(new_list1, Iterator)) # True
3.遍历迭代器
通过for循环遍历
# 通过for循环遍历foriinnew_name: print(i) '''james'''
通过next()函数遍历
# 通过next()函数遍历, next()new_list1.__next__()print(next(new_list1)) # 1print(next(new_list1)) # 2print(next(new_list1)) # 3print(new_list1.__next__()) # 4print(new_list1.__next__()) # 5
next()函数获取,按照从前往后的顺序,每次只获取一个、每个值只能获取一次,当获取次数超过总长度时会报错StopIteration,可使用如下写法:
whileTrue: try: print(next(new_list1)) exceptStopIteration: break
4.可迭代对象 VS 迭代器对象
先来打印一下可迭代对象和迭代器的属性列表
# 获取可迭代对象的属性列表list_2= [1, 2, 3] print(dir(list_2)) ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
通过打印结果中可以看出,可迭代对象方法列表中实现了__iter__方法,但并没有实现__next__方法;
# 获取迭代器对象的属性列表list_2= [1, 2, 3] print(dir(iter(list_2))) ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
通过打印结果中可以看出,可迭代对象方法列表中既实现了__iter__方法,也实现了__next__方法;
所以,可以总结出迭代器(Iterator)与可迭代对象(Iterable)的区别:
- 迭代器一定是可迭代对象,因为同时实现了__iter__方法和__next__方法,可以通过next()方法获取下一个值,但是每个值只能获取一次;
- 但可迭代对象并不一定是迭代器,例如列表、字典、字符串,它们只实现了__iter__方法,如果想变成迭代器对象可以使用iter()进行转换;
- 迭代器和可迭代对象都可以用作for循环遍历;
- 只要可以用for循环遍历的都是可迭代对象,只要可以用next()函数遍历的都是迭代器对象;
5.使用迭代器的意义
使用for循环也可以遍历列表、字典等可迭代对象,列表、字典等可迭代对象是一次性将所有元素都加载到内存中,当可迭代对象的长度较长时,会占用系统资源,而使用迭代器,则是每次只获取一个,返回一个,不会造成资源浪费,在性能上大大优于未使用迭代器的场景
6.自定义一个迭代器
自定义一个迭代器,随机生成10个0-100的整数
classRandomIterator(object): def__init__(self): self.count=0# 只有使用__iter__方法才能使用for循环进行遍历,否则只能用next()获取迭代对象# 使用了__iter__方法的都是可迭代对象def__iter__(self): returnself# 使用了__next__方法的都是迭代器对象def__next__(self): ifself.count==10: raiseStopIterationnumber=random.randint(0, 100) self.count+=1returnnumberrandom_iter=RandomIterator() foriinrandom_iter: print(i) '''49359247291123573857'''
小结
- 迭代器一定是可迭代对象,但可迭代对象不一定是迭代器;
- 要想自己实现迭代器,必须实现__iter__方法和__next__方法。