what's the python之可迭代对象迭代器与生成器(附面试题)

Posted zhuminghui

tags:

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

可迭代对象

字符串、列表、元祖、集合、字典都是可迭代的,数字是不可迭代的。(可以用for循环遍历取出内部元素的就是可迭代的)

如何查看一个变量是否为可迭代:

from collections import Iterable
                             
l = [1,2,3,4]                
t = (1,2,3,4)                
d = {1:2,3:4}                
s = {1,2,3,4}                
                             
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(d,Iterable))
print(isinstance(s,Iterable))
#结果为True就是可迭代,False就是不可迭代

可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义就是内部实现了__iter__方法,即可迭代对象中封装有__iter__方法。

 

迭代器

迭代器:用变量调__iter__后就可以生成一个迭代器,迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。

l = [1,2,3,4]
l_iter = l.__iter__()#l_iter只是一个接受的变量
item = l_iter.__next__()#利用迭代器取值
print(item)#1
item = l_iter.__next__()
print(item)#2
item = l_iter.__next__()
print(item)#3
item = l_iter.__next__()
print(item)#4
item = l_iter.__next__()
print(item)#超出限度,报错

上步在最后出现了报错情况,为了使程序不报错,可以在取完了的最后将其终止掉:

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

 

 生成器

生成器:(本质就是一个迭代器,不过是由程序员写出来的才叫生成器,内置的就叫迭代器)

  1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行,惰性。

  2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

 

简易生成器:

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

g1 = func()
print(g1 : ,g1)       #打印g1可以发现g1就是一个生成器
print(-*20)   #我是华丽的分割线
print(next(g1))
time.sleep(1)   #sleep一秒看清执行过程
print(next(g1))#每print一次next才会出来一个yield的值,不然就挂在上一个yield上不继续执行

生成器有什么好处呢?就是不会一下子在内存中生成太多数据,只有在你要的时候才会给你你要的数据

生成器应用的几个小栗子:

有关衣服订单:

技术分享图片
def produce():
    """生产衣服"""
    for i in range(2000000):
        yield "生产了第%s件衣服"%i

product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g:         #要一批衣服,比如5件
    print(i)
    num +=1
    if num == 5:
        break

#到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
#剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
View Code

生成器监听文件输入的栗子:

技术分享图片
import time

def tail(filename):
    f = open(filename)
    f.seek(0, 2) #从文件末尾算起
    while True:
        line = f.readline()  # 读取文件中新的文本行
        if not line:
            time.sleep(0.1)
            continue
        yield line

tail_g = tail(tmp)
for line in tail_g:
    print(line)
View Code

计算移动平均值(类似于年化收益):

技术分享图片
def averager():
    total = 0
    day = 0
    average = 0
    while True:
        term = yield average
        total += term
        day += 1
        average = total/day


g_avg = averager()
next(g_avg)
print(g_avg.send(10))
print(g_avg.send(12))
print(g_avg.send(13))
View Code

 

yield from可以在实行for循环的效果的同时将代码变少:

def gen1():
    for c in AB:
        yield c
    for i in range(3):
        yield i

print(list(gen1()))#[‘A‘,‘B‘,1,2,3]




#简化版本
def gen2():
    yield from AB
    yield from range(3)

print(list(gen2()))#[‘A‘,‘B‘,1,2,3]

 

列表推导式和生成器表达式:(这里用一个小故事讲解知识点)

 

技术分享图片
#为了彰显高富帅本质,一口气买了十个茶叶蛋,将他们依次排开并编号,拍照发到朋友圈

egg_list=[茶叶蛋%s %i for i in range(10)] #列表解析

#可是这十个茶叶蛋一口气吃不完啊,要吃也就是一个一个吃,那么就吃一个拍一个照吧

eat=(茶叶蛋%s %i for i in range(10))#生成器表达式
print(eat)
print(next(eat)) #next本质就是调用__next__
print(eat.__next__())
print(next(eat))
高富帅与茶叶蛋

 

 

 

总结:

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

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

3.Python使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。

 

 

附:与生成器相关的面试题:

技术分享图片
def demo():
    for i in range(4):
        yield i

g=demo()

g1=(i for i in g)
g2=(i for i in g1)

print(list(g1))#[0,1,2,3]
print(list(g2))#[]
面试题1
技术分享图片
def add(n,i):
    return n+i

def test():
    for i in range(4):
        yield i

g=test()
for n in [1,10]:
    g=(add(n,i) for i in g)

print(list(g))#[20,21,22,23]
面试题2

 

以上是关于what's the python之可迭代对象迭代器与生成器(附面试题)的主要内容,如果未能解决你的问题,请参考以下文章

what's the python之异常处理

what's the python之函数及装饰器

what's the python之模块

what's the python之面向对象

python之可迭代对象

what's the python之自定义模块和包