SEQ19 深入理解迭代器和生成器
1 四个概念区分:容器、可迭代对象、迭代器、生成器;
a.“容器”:直观感受就是多个’类似’数据结构的元素组在一起单元,比如,数组、元组、字典都是容器。所有的容器都是可迭代的。
b.“可迭代对象(interable)”:Python中一切皆对象。所以Python中只要是可迭代(类似使用for in obj:)的对象,都是可迭代对象。
比如:容器就是可迭代对象;“迭代”:不等于简单的重复。迭代包含了有规律的变化
c.“迭代器(interator)”:“可迭代对象” 不等于"迭代器","可迭代对象"通过iter()函数可以得到一个迭代器,迭代器通过next()得到
下一个元素。
PS:首先要明一点,迭代器是一个类(class),比如:class list,class set,class str 都是class
d.“生成器(generator)”:是一种特特类型的迭代器,但反之不成立(即迭代不一定是生成器)。当生成器所有元素都遍历完后,会抛出StopIteration异常。
2 如何判断对象是否可迭代?
a. iter()函数,如果可迭代,则返回一个可迭代对象,否则报错;
b. from collections import Iterable
instance(v, type)
#code 1
from collections import Iterable
params = [1234, '1234', [1, 2, 3, 4], set([1, 2, 3, 4]), {1:1, 2:2, 3:3, 4:4}, (1, 2, 3, 4)]
for i in params:
tag = isinstance(i, Iterable)
print(f"对象:{i} 是否可迭代:{tag}:")
3 如何构建一个可迭代对象?
1)使用[]
# code 2
from collections import Iterable
a = [i for i in range(1001)]
print(isinstance(a, Iterable))
2)实例化一个迭代器,得到一个可迭代对象
# code 3
# BookCollections() 是个迭代器
books = BookCollections()
4 迭代器(Iterator)
1) 迭代器–如何构建一个迭代器?
迭代器的本质:迭代器是个类,迭代器是个类,迭代器是个类~~~重要事情说三遍!
需要在类中实现__iter__()和__next__() 方法,就构建了一个迭代器。
# code 4
class BookCollections(object):
def __init__(self):
self.data = ["《往事》", "《只能》", "《回味》"]
self.cur = 0
def __iter__(self):
return self
def __next__(self):
if self.cur > len(self.data):
raise StopIteration()
r = self.data[self.cur]
self.cur += 1
return r
from collections import Iterable
books = BookCollections()
print(f'books的类型{isinstance(books,Iterable)}')
print(f'BookCollections()的类型{isinstance(BookCollections(), Iterable)}')
2) 迭代器–迭代器的“一次性”
迭代器具有“一次性”的特性,即只能遍历一次。因为生成器也是一种懒人版本的迭代器,所以也有“一次性“的特性。
# code 5
books = BookCollections()
for book in books:
print(book)
for book in books:
print(book)
#如上第二个for循环不会打印任何
若需要多次遍历,需要:
a.复位重新生成一个可迭代对象;
# code 6
book1 = BookCollections()
books = BookCollections()
b.使用copy.copy()或者copy.deepcopy()
books = BookCollections()
import copy
books_copy = copy.copy(books)
for book in books:
print(book)
for book in books_copy:
print(book)
5 生成器(generator)
生成器的本质:是一种函数,一种算法,边执行,边“生成”。如
生成器,可以理解为“懒人版本的迭代器”。
1) 如何声明一个生成器
Python中用小括号括起来即表示生命一个“生成器”,如(i for i in range(1001))
a = (i for i in range(1001))
print(type(a))
-----------------
<class 'generator'>
2)一个对比实例
需求
获取0~10000之间的每个数的和
方案
方案1:常规方案:列表 + 循环
n = [i for i in range(10001)]
sum = 0
for i in n:
sum += i
print(sum)
方案2:生成器方案
def gen(max):
n = 0
while n <= max:
yield n
n += 1
sum = 0
for i in gen(10000):
sum += i
print(sum)
优劣对比
方案一中,n是直接保存在内存中的一个类别,占用很多内存,如果数据多到超过服务器内存时,会出现OOM的异常。
方案二种,生成器保存的实际上是一种算法,每次返回yield出的值,所以不会占用太大的内存。
3) return和yield关键字
return:在程序函数中返回某个值,返回之后函数不在继续执行,彻底结束。
yield:带有yield关键字的函数是一个迭代器,函数遇到yield关键字,则返回yield后的值后,然后跳到next()函数从yield处继续执行,直到程序结束。
def gen(max):
n = 0
while n <= max:
yield n
n += 1
#########################
for i in gen(5):
print(i)
# 等价于
g =gen(5)
i = 1
while i <= 6:
i += 1
print(next(g))