概述
首先理解下面的这边概念内容
1、可迭代对象:元素一开始就已经存在,比如常用的字符串,列表(list: [0, 1, 2]),元组(tuple: (0, 1, 2)),字典(dict: {0:0, 1:1, 2:2}),集合(set: set([0, 1, 2]))
2、迭代器:可迭代对象调用iter()方法返回的对象,就是一个迭代器,可以使用next()方法实现遍历,可以使用iter()函数判断是否是可迭代对象,比如下面的这些对象
def is_iterable(param):
try:
iter(param)
return True
except TypeError:
return False
params = [
12,
"123",
[1,2,3,"ad"],
(3,3,21,"er"),
{3,12,"ad","asd"},
{1:"ad", 2:"er"}
]
for i in params:
print(f"{i} is iterable? {is_iterable(i)}")
执行结果:
再来看可迭代对象是什么样的:
list = [i for i in range(3)]
print(f"list is {list}")
l_iter = iter(list)
print(f"l_iter is {l_iter}")
print(next(l_iter))
print(next(l_iter))
print(next(l_iter))
print(next(l_iter))
执行结果:
列表执行iter()函数返回一个迭代器对象list_iterator,执行next()函数可以实现遍历,因为列表的长度是3,超过列表的长度时,执行next()函数,会报StopIteration异常
3、生成器:可以理解成特殊的迭代器,元素只有调用next()函数的时候才会生成,在Python中是用小括号括起来的,比如(i for i in range(10))
gena = (j for j in range(3))
print(f"gena is {gena}")
print(next(gena))
print(next(gena))
print(next(gena))
print(next(gena))
运行结果:和list的结果一样,只不过生成器是执行next()函数的时候才生成的内容
4、然后我们来看看for循环对于迭代器的重要作用:
#迭代器
list = [i for i in range(3)]
print(f"list is {list}")
for it in list:
print(f'this is list: {it}')
l_iter = iter(list)
print(f"l_iter is {l_iter}")
for it in l_iter:
print(f"this is l_iter: {it}")
#生成器
gena = (j for j in range(3))
print(f"gena is {gena}")
for it in gena:
print(f"this is gena: {it}")
执行结果:
也就是说,我们遍历迭代器的时候,不用每次都调用iter()和next(),for循环直接把这两个函数的操作隐视化了,很方便,还有一点值得注意的是,for循环可以遍历容器(list),也可以遍历迭代器和生成器,可能底层实现是根据对象的类型调用的不同的函数
5、yield对于生成器的作用
生成器不仅可以用括号生成,使用函数也可以创建生成器,yield就是其中的关键
#函数表示生成器,生成器验证数学中的一个恒等式
#(1 + 2 + 3 + ... + n)^2 = 1^3 + 2^3 + 3^3 + ... + n^3
def genaretor(k):
print(f"this is genaretor{k}")
i = 1
while True:
yield i ** k
i += 1
gen1 = genaretor(1)
gen3 = genaretor(3)
print(gen1)
print(gen3)
def sum(n):
sum1, sum2 = 0, 0
for i in range(n):
next1 = next(gen1)
next2 = next(gen3)
print(f"next1 is {next1}, next2 is {next2}")
sum1 += next1
sum2 += next2
print(f"(1+2+3+4+...+n)^2 is {sum1 * sum1}, (1^3 + 2^3 + 3^3 +...+ n^3) is {sum2}")
sum(10)
执行结果:
首选,print打印的gen1,gen3都是一个生成器,如之前所说,我们可以用next()函数执行遍历,next1和next2的值就是next()调用生成器的结果
这里说明一下yield这个魔术,可以理解成第一次执行到yield的时候,跳出这个函数,yield 后面表达式的执行结果返回给next()函数,上面的函数就是赋值给next1
在sum()函数中,第一次执行next()函数的时候,进入生成器gen1,然后函数print,执行到yield 1**1的时候跳出这个函数,1**1返回给next()函数,赋值给next1,然后外层的for循环再次执行到next()函数的时候,暂停的程序又重新开始了,从yield往下执行,局部变量i还是暂停时的值,i可以一直累加,所以只要一直next(),生成器就可以一直生成值
6、生成器的骚操作
看下面的问题:判断一个序列是不是另一个序列的子序列,子序列则指的是,一个列表的元素在第二个列表中都按顺序出现,但是并不必挨在一起。
举个例子,[1, 3, 5] 是 [1, 2, 3, 4, 5] 的子序列,[1, 4, 3] 则不是。
如果不使用生成器,我们需要遍历第二个序列,找到第一个序列和第二个序列一样的值一样的时候,第一个序列的index前进一位,第一个index移出第一个序列最后一个元素的时候,返回 True,否则返回 False。
代码如下:
#不使用生成器
def is_subsequence(sub_list, up_list):
sub_index = 0
for i in up_list:
if i == sub_list[sub_index]:
sub_index += 1
if sub_index > len(sub_list) - 1:
break
# 当sub的index遍历完sub_list的时候就是子序列
if sub_index > len(sub_list) - 1:
return True
else:
return False
print(is_subsequence([1,2,3], [1,4,2,3,5]))
print(is_subsequence([1,3,2], [1,4,2,3,5]))
print(is_subsequence([1,3,3], [1,4,2,5]))
print(is_subsequence([1,3,2,6,6], [1,3,2,6,5]))
执行结果:
如果是使用生成器的话,可以大大的减少代码行数
代码如下:
#使用生成器
def is_subsequence_genaretor(sub_list, up_list):
# 生成一个迭代器
up_iter = iter(up_list)
# all里面的值全为true的时候返回true
return all((i in up_iter) for i in sub_list)
print(is_subsequence_genaretor([1,2,3], [1,4,2,3,5]))
print(is_subsequence_genaretor([1,3,2], [1,4,2,3,5]))
print(is_subsequence_genaretor([1,3,3], [1,4,2,5]))
print(is_subsequence_genaretor([1,3,2,6,6], [1,3,2,6,5]))
结果如下:
其中令人难以理解的部分可能就是(i in up_iter)这个东西了,因为up_iter是一个迭代器,所以(i in up_iter)这部分代码,可以理解成下面这段代码:
while True:
val = next(b)
if val == i:
yield True
我们来看看 in在迭代器和容器(set,list,dict等)里面使用的区别:
#容器里面的in
t_list = [1,3,4,2]
print(f"1 in t_list? {(1 in t_list)}")
print(f"2 in t_list? {(2 in t_list)}")
print(f"3 in t_list? {(3 in t_list)}")
print(f"4 in t_list? {(4 in t_list)}")
# 迭代器里面的in
i_list = iter(t_list)
print(f"1 in i_list? {(1 in i_list)}")
print(f"2 in i_list? {(2 in i_list)}")
print(f"3 in i_list? {(3 in i_list)}")
print(f"4 in i_list? {(4 in i_list)}")
执行结果:
可以看到,迭代器里面的in,是有执行next()这个操作的了
所以上面的(i in up_iter) for i in sub_list,相当于先遍历sub_list赋值给 i, 然后再往后遍历up_iter,判断i是否在up_iter里面,并且是next()执行一直往后,直到遍历到最后返回结果
最后
以上就是天真日记本为你收集整理的python的迭代器与生成器的全部内容,希望文章能够帮你解决python的迭代器与生成器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复