迭代器和生成器

迭代器

迭代器协议:对象必须提供一个next方法 即x.next()存在

需要遵循迭代器协议

python 中的for 循环本质是引用了_iter_ 然后才用的next方法进行循环 .例如:

i = [1,2,3]
i1= i.__iter__()
print(i1.__next__())=========1
print(i1.__next__())=========2
print(i1.__next__())=========3

next 方法:

next 方法相当与 x._iter_()._next_()

i = [1,2,3]
i1= i.__iter__()
print(i1.__next__())=======>结果是1
print(next(i1))=========》结果是2 因为相当与for中的内循环

迭代器运行的方法:

1,生成器._next_()

def hello():
yield 1
yield 3
yield 5

l = hello()
s1= l.__next__()=====>同下解释,结果为1
print(s1)
s2 = l.__next__()====》同下结果:结果为3
print(s2)

2, next(生成器)

def hello():
yield 1====>第一次返回值是1
yield 3====》第二次返回值是3
yield 5====》第三次返回值是5

l = hello()
s1= next(l)
print(s1)=====》第一次运行所以结果是1
s2 = next(l)
print(s2)=====》第二次运行所以返回结果为3

3,.send () 使用send 时需要先运行 send(None)/ next(),再继续运行send(),否则会报错

def hello():
yield 1======#例如:x =yield 1
yield 3
yield 5

l = hello()
s1= l.send(None)
print(s1)=======1
s2= l.send(5)
print(s2)=======3
s3= l.send(3)
print(s3)======5

send() 中括号的数字只是yield 1 整体的值 例如上述 send(5) 中5 是赋值给上述内容中的x 即x = 5.

注意send()中值与yield的返回值没有一点关系

---------------------

def f():
print('ok')
yield 2

next(f())#结果是ok
print(next(f()))
#结果是:
ok
2

生成器

 生成器:可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自己内置的_iter_()方法)所以生成器是可迭代对象

生成器只能遍历一次。for,sum ,list 都可以遍历生成器

def test():
for i in range(4):
yield i
t = test()
for i in t:
print(i)======>结果是0,1,2,3===遍历一次生成器t

t1 = (i for i in t)
print(list(t1))====》结果是[] 因为生成器t之前已经被遍历了一次

 *************************************

def test():
for i in range(4):
yield i
t = test()========》生成器t 本身是没有值的只是一个内存地址

t1 = (i for i in t)===》生成生成器t1
print(list(t1))====>遍历一次生成器t1,结果是 [0,1,2,3]
t2 = (i for i in t1)
print(list(t2))=====》结果是:[],因为已经遍历一次t1所以结果是[].

-生成器函数使用yield 语句而不是return语句返回结果。yield 语句一次返回一个结果。每个结果中间挂起函数的状态,一边下次从离开的地方继续执行。

def test():
yield 1
yield 3
yield 5
s = test()
print(s)========><generator object test at 0x7fe18c174a98>
print(s.__next__())====>1
print(s.__next__())=====>3
print(s.__next__())=====>5

 -生成器表达式

三元表达式(不能大于3元)

name = 'alisa'
#'正确' if name == 'alisa' else '错误'====>此处代表的意思是:如果name 等于alisa,结果返回正确,如果不等于,返回错误,此处就是三元表达式
s='正确' if name == 'alisa' else '错误'
print(s)

列表解析

将一筐鸡蛋给一个人,将这筐鸡蛋用列表表示。

一般代码如下:

egg = []
for i in range(5):
egg.append('鸡蛋%s'%i)
print(egg)======》['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']

用三元表达式:

egg = ['鸡蛋%s'%i for i in range(5)]  ======》此处是二元,返回结果是一元,for循环是一元
print(egg)=========》['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4']

 求大于2的鸡蛋列表

egg1 = ['鸡蛋%s' % i for i in range(5) if i > 2]
print(egg1)=========>['鸡蛋3', '鸡蛋4']

 求小于2的鸡蛋列表

egg1 = ['鸡蛋%s' % i for i in range(5) if i < 2]
print(egg1)=========>['鸡蛋0', '鸡蛋1']

 求带回母鸡,自己让母鸡下蛋

egg1 = ('鸡蛋%s' % i for i in range(5))=====  egg1 相当于一个生成器
print(egg1.__next__())=====>鸡蛋0
print(next(egg1))========》鸡蛋1

总结:把列表解析的[]换成()得到就是生成器表达式

         列表解析与生成器表达都是一种便利的编程方式不过生成器更节省内存 

 补充:浅拷贝和深拷贝 .copy()

.copy 是浅拷贝只能拷贝第一层 而 = 是深拷贝

浅拷贝:

a = [[1,2],4,5]
b = a.copy()
b[1]= 123
print(a,b)======》 a=[[1, 2], 4, 5] b=[[1, 2], 123, 5] 由于浅拷贝,所以a 不变

另外请注意这种的除外:
a = [[1,2],4,5]
b = a.copy()
b[0][0]= 123
print(b,a)=====>a随着b 改变 是因为改变的是列表中的列表,所以 a 会变
***********************

深拷贝copy.deepcopy() 或者直接=

a = [[1,2],4,5]
c = a
c[1]= 123
print(a,c)======> [[1, 2], 123, 5] [[1, 2], 123, 5] 深拷贝所以a 随着c改变
*******************************************************************
a = [[1,2],4,5]
c = a
c[0][0]= 123
print(c,a)=====>[[1, 2], 123, 5] [[1, 2], 123, 5] a随着c 改变 是因为是深拷贝

***********************************************

a = [[1,2],4,5]
b = a.copy()===》浅拷贝只能拷贝第一层 ,因此b =[[1,2],4,5]
c = a====>深拷贝
print(a,b,c)====》[[1, 2], 4, 5] [[1, 2], 4, 5] [[1, 2], 4, 5]
b[0]='ni'; c[0]= 6
print(b,a,c)======>结果是:b=['ni',4,5] a = [6,4,5] c = [6,4,5] 由于b 是浅拷贝所以a 不变,还是原来的;但是c是深拷贝,所以a随着c 改变

原文地址:https://www.cnblogs.com/wode110/p/14683294.html