Day12 Python基础之生成器、迭代器(高级函数)(十)

时间:2023-03-09 09:44:06
Day12  Python基础之生成器、迭代器(高级函数)(十)

https://www.cnblogs.com/yuanchenqi/articles/5769491.html

1. 列表生成式

我现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我要求你把列表里的每个值加三次方,你怎么实现?你可能会想到2种方式

 a=[0,1,2,3,4,5,6,7,8,9]
b=[]
for i in a:
b.append(i+1)
a=b
print(a)

普通版本

 a=map(lambda x:x+1,range(10))
print(a,type(a))
for i in a:
print(i) 输出结果:
<map object at 0x0272A4D0> <class 'map'>
1
2
3
4
5
6
7
8
9
10

文艺版本

 (1)
t=[0,1]
a,b=t
print(a)
print(b)
输出结果:
0
1
(2)
t=[0,1,2]
a,b=t
print(a)
print(b)
输出结果:
ValueError: too many values to unpack (expected 2)
(3)
t=[0,1]
a,b,cc=t
print(a)
print(b)
print(c)
输出结果:
ValueError: not enough values to unpack (expected 3, got 2)

小知识点

 def f(n):
return n**3
a=[f(x) for x in range(10)]
print(a,type(a)) 等价于
a=[x**3 for x in range(10)]
print(a,type(a))
输出结果:
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729] <class 'list'>

装逼版本

2. 生成器(generator)

生成器的创建方式有两种:()和yield

 a=(x**3  for x in range(10))
print(a,type(a)) 等价于
def f(n):
return n**3
a=(f(x) for x in range(10))
print(a,type(a)) 输出结果:
<generator object <genexpr> at 0x02DC34B0> <class 'generator'>

简单生成器之()生成演示

生成器数据类型的变量指向的内存地址,根本就没有任何数据在内存中,也没有存储在任何地方。

(类比理解:列表是将数据存储在变量指向的内存空间的,这就相当于你冰箱里面放了十道菜,你想吃哪个就去拿,这是占用一定的空间的,为了解决这个问题,我们有了生成器,就好比你拥有了一个有脾气的厨师,让厨师给你现做现吃,做哪个你就吃哪个好了,在生成器s中可以用生成器内置方法s.__next__()或者python内置函数next(s)这个方法按顺序生成值,这取决于你生成器的本身的特性。建议使用next(s))

生成生成器对象里面的值

 a=(x*2 for x in range(10))
print(a,type(a))
print(a.__next__())
print(next(a))
print(next(a))
print(next(a))
输出结果:
<generator object <genexpr> at 0x028B34B0> <class 'generator'>
0
2
4
6

next()生成值

注:生成器就是一个可迭代对象,迭代器也是可迭代对象

 a=(x*2 for x in range(4))
print(a,type(a)) for i in a:
print(i) 输出结果:
0
2
4
6

遍历生成器

注:(1)for循环可遍历可迭代对象,有__iter__方法的都是可迭代对象内部的方法,iter()是内置函数

(2)for循环遍历可迭代对象的三个步骤:

      • 调用可迭代对象的iter方法,返回一个迭代器对象
      • 不断调用迭代器的next方法
      • 处理stopiteration异常

while:

try:

i=next(generator) 

except StopIteration

break 

(3)当内存中的数据,没有变量引用的时候(即没有变量指向该内存地址),该数据就会被python的解释器当垃圾清除掉

这样就算遍历生成器,也不会占用大量内存,因为i的指向一直在更新,没有被引用的数据就会被清除

 def f():
print('Hello')
yield 1
print('Ok')
yield 2
g=f()
print(g,type(g))
输出结果:
<generator object f at 0x033634B0> <class 'generator'>

简单生成器之yield生成演示

注:没有yield就是普通的函数,有yeild,定义的函数f()就是一个生成器对象,有几个yield就相当于几道菜。

生成生成器对象里面的值

 def f():
print('Hello')
yield 1
print('Ok')
yield 2
g=f()
next(g)
next(g)
输出结果:
Hello
Ok

next()

注:

(1)每调用一次next(g),就执行一遍g函数,以yield为结束点,返回1(相当于return结束函数的运行),再执行一遍next(g),以上次的结束点为起点,继续执行g函数,并返回2

(2)可通过yield实现在单线程的情况下实现并发运算的效果,即伪并发,CPU切换速度特别快,以至于我们不觉得有切换这一过程

 def f():
print('Hello')
yield 1
print('Ok')
yield 2
g=f() for i in g:
print(i)
输出结果:
Hello
1
Ok
2

for循环遍历生成对象

注:for循环遍历生成对象g,以yield结束标志执行函数内容,并打印出了yield返回值

 def fibo(N):
Max=N
n,before,after=0,0,1
while n<Max:
# print(after)
yield after
before,after=after,before+after
n+=1
g=fibo(8)
# print(next(g))
# print(next(g))
# print(next(g))
for i in g:
print(i)

yield生成斐波那契数列

生成器对象的send方法

 def fibo(N):
Max=N
n,before,after=0,0,1
while n<Max:
# print(after)
count=yield after
print(count)
before,after=after,before+after
n+=1
g=fibo(8) g.send(None) #相当于next(g),先进入生成器对象,遇到yield,返回after后结束
g.send('eee') #从上一次结束点开始,继续程序,将send的参数赋值给count,继续执行后面的语句,直到再次遇到yield
输出结果:
eee

send方法传参数

注:进入生成器后(next,send(None))再能send传参数

3. 迭代器(iterator)

生成器都是迭代器,迭代器不一定是生成器;

可迭代对象(Iterable)不一定是迭代器(Iterator),通过iter方法可以把可迭代对象变成迭代器(迭代器对象),这是因为可迭代对象里面有__iter__方法。

什么是迭代器:需要满足两个条件:(1)有iter方法(2)有next方法

 from collections import Iterable,Iterator
d=[1,2,3,4,5,6]
a=iter(d)
print(a,type(a))
# print(next(a))
# # print(next(a))
# for i in a:
# print(i)
print(isinstance(d,Iterable)) #判断d是不是可迭代对象
print(isinstance(d,list)) #判断d是不是列表
print(isinstance(d,Iterate)) #判断的是不是迭代器

迭代器

Day12  Python基础之生成器、迭代器(高级函数)(十)