python之迭代器与生成器

Posted -零

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python之迭代器与生成器相关的知识,希望对你有一定的参考价值。

python之迭代器与生成器

 

可迭代

假如现在有一个列表,有一个int类型的12345。我们循环输出。

list=[1,2,3,4,5]
for i in list:
    print(i)
for i in 12345:
    print(i)

 

结果:

Traceback (most recent call last):
  File "C:/Pycham/生成器与迭代器/test1.py", line 6, in <module>
    for i in 12345:
TypeError: ‘int‘ object is not iterable
1
2
3
4
5

 

报错显示:1234不是可以被迭代的。

那python中哪些是可迭代的:字符串、列表、元组、字典、集合。
for循环工作机制:for循环在循环一个对象的时候,会调用这个对象的iter方法,得到迭代器,然后在调用这个迭代器的next方法,去获得这个迭代器中包涵的每个值。
现在可能我们不太明白,什么是iter方法,什么是迭代器,什么是next方法。

  

 

迭代器

但是如果只是将数据集内的数据“一个挨着一个的取出来,for循环就可以做到,为什么要使用迭代器呢?迭代器是什么?
迭代器能迭代的一定是可以迭代的数据类型。
如果我们要使用迭代器,一定要将可以被迭代的数据集转为迭代器,使用__iter__()

  

#列表生成式
list=[1,2,3,4,5]
#生成器
gen=list.__iter__()
print(list)
print(gen)

结果:
[1, 2, 3, 4, 5]
<list_iterator object at 0x0000000002627278>

 

迭代器的三个方法

iter_l = [1,2,3,4,5,6].__iter__()
#获取迭代器中元素的长度
print(iter_l.__length_hint__())
#根据索引值指定从哪里开始迭代
print(iter_l.__setstate__(2))
#一个一个的取值
print(iter_l.__next__())

  

结果:
6 None 3

 

循环输出迭代器的内容

注意:

很重要的特性,就是不可逆,只能前进,不能后退。

如果迭代的次数超过里面的数据,就会报错。

l = [1,2,3,4]
l_iter = l.__iter__()
while True:
    try:
        item = l_iter.__next__()
        print(item)
    except StopIteration:
        break

  

总结:一个对象是否可迭代,全都取决于这个对象是否有iter方法,调用对象的iter方法,就回返回一个迭代器,这个迭代器一定具有next方法,在调用这个迭代器的next方法时,迭代器就回返回它的下一个值,当迭代器中没有
值可以返回了,就回抛出一个名为StopIteration的异常,停止迭代。
for循环的工作机制,可以让我们遍历任何一个可迭代的数据集。
虽然序列类型字符串,列表,元组都有下标,你用下标的方式访问。
但是非序列类型像字典,集合,文件对象这样的数据类型也是可迭代的。

  

 

生成器

通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator

生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。

生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像
是迭代器。 总结:生成器是个比较特殊的可迭代对象,它与其他的可迭代对象不太一样的地方,其他的可迭代对象需要调用iter方法,返回个迭代器对象,然后通过迭代器对象去执行next方法,获取迭代器中的值,但是生成器直接可以被迭代,无需执行iter方法。

  

  
生成器Generator:

  本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

  特点:惰性运算,开发者自定义

  

 

初始生成器

import time
def genrator_fun1():
    a = 1
    print(现在定义了a变量)
    yield a
    b = 2
    print(现在又定义了b变量)
    yield b

g1 = genrator_fun1()
print(g1 : ,g1)       #打印g1可以发现g1就是一个生成器
print(-*20)   #我是华丽的分割线
print(next(g1))
time.sleep(1)   #sleep一秒看清执行过程
print(next(g1))

 

 

 

 

python中生成器有两种表达形式

函数式生成器:在常规的函数中定义的生成器,语句的返回值不再使用return去返回,而是使用yield关键字每次返回一个结果,一个函数中不可以有多个return,但是可以有多个yield,函数中的每一个yield都会返回一个结果,每执行一个yield,函数的执行状态都会被‘挂起’可以理解
为暂停,下次继续调用这个函数的时候,会从上次挂起的位置继续向下执行。

 

def func1():

    yield 1

    print("第一个yield执行完成~")

    yield 2

    print("第二个yield执行完成~")

    yield 3

    print("第三个yield执行完成~")


for i in func1():
    print(i)

  

结果:
1 第一个yield执行完成~ 2 第二个yield执行完成~ 3 第三个yield执行完成~

  

 

生成器表达式:使用类似于列表推导式的方法,但是返回的对象不再是一个列表,而是一个可以按需生成结果的一个对象(生成器)。
只要把一个列表生成式的[]中括号改为()小括号,就创建一个generator

 

#列表生成式
lis = [x*x for x in range(10)]
print(lis)
#生成器
generator_ex = (x*x for x in range(10))
print(generator_ex)
 
结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x000002A4CBF9EBA0>

  

 

for循环输出生成器的值

#生成器
generator_ex = (x*x for x in range(10))
for i in generator_ex:
    print(i)
     
结果:
0
1
4
9
16
25
36
49
64
81
所以我们创建一个generator后,基本上永远不会调用next(),而是通过for循环来迭代,并且不需要关心StopIteration的错误(迭代超过长度)。

 

使用生成器的优点:

延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。

  

 

最后示例:

import time

def cumtom(name):
    print(‘%s准备吃包子‘ %name)
    time.sleep(1)
    while 1:
        count=yield
        print(‘%s吃到第%d个包子‘ %(name,count))

def producter():
    con1.__next__()
    con2.__next__()
    n=1
    while 1:
        time.sleep(1)
        print(‘已经生产出来%d、%d个包子‘ %(n,n+1))
        #通过send方法通知
        con1.send(n)
        con2.send(n+1)
        n+=2


con1=cumtom(‘cumtom1‘)
con2=cumtom(‘cumtom2‘)
producter()

  

cumtom1准备吃包子
cumtom2准备吃包子
已经生产出来1、2个包子
cumtom1吃到第1个包子
cumtom2吃到第2个包子
已经生产出来3、4个包子
cumtom1吃到第3个包子
cumtom2吃到第4个包子
已经生产出来5、6个包子
cumtom1吃到第5个包子
cumtom2吃到第6个包子
已经生产出来7、8个包子
cumtom1吃到第7个包子
cumtom2吃到第8个包子
已经生产出来9、10个包子
cumtom1吃到第9个包子
cumtom2吃到第10个包子
已经生产出来11、12个包子
cumtom1吃到第11个包子
cumtom2吃到第12个包子
已经生产出来13、14个包子
cumtom1吃到第13个包子
cumtom2吃到第14个包子
已经生产出来15、16个包子
cumtom1吃到第15个包子
cumtom2吃到第16个包子

  

以上是关于python之迭代器与生成器的主要内容,如果未能解决你的问题,请参考以下文章

6Python全栈之路系列之迭代器与生成器

6Python全栈之路系列之迭代器与生成器

Python高手之路python基础之迭代器与生成器

python 基础之迭代器与生成器

python基础-函数之装饰器迭代器与生成器

迭代器与生成器 全面解析