python之路16--之迭代器与生成器

一、迭代器

1、什么是迭代器

        迭代,顾名思义就是重复做一些事很多次(就现在循环中做的那样)。迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),它是访问可迭代序列的一种方式,通常其从序列的第一个元素开始访问,直到所有的元素都被访问才结束。 [注意]:迭代器只能前进不能后退

 

2、迭代器的优点

        从容器类型中一个一个的取值,会把所有的值都取到(节省内存空间)迭代器并不会在内存中在占用一大块内存,而是随着循环,每次生成一个,每次next一个给程序

 

3、迭代器和可迭代类型

     迭代器:迭代器可以通过__next__方法从迭代器中一个一个取值,迭代器同时含有__iter__()和__next__()方法

   可迭代类型:可被for循环的类型都是可迭代的,可迭代的类型都含有__iter__方法;
   可迭代协议:只要含有__iter__方法的都是可迭代的,
迭代器协议:内部含有__next__和__iter__方法的就是迭代器

 

4、如果判断一个类型是不是迭代器

1、

from collections import Iterable
from collections import Iterator
print(isinstance([],Iterator))           #判断[]是不是一个迭代器
print(isinstance([],Iterable))           #判断[]是不是可迭代的类型

2、

# print('__iter__' in dir(int))
# print('__iter__' in dir(bool))
# print('__iter__' in dir(list))
# print('__iter__' in dir(dict))
# print('__iter__' in dir(tuple))
# print('__iter__' in dir(enumerate([])))
# print('__iter__' in dir(range(1)))
#只要是能被for循环的数据类型就一定拥有__iter__方法,直要含有__iter__()方法就可以判断为这是一个迭代器类型

5、获取迭代器

print([].__iter__())        #一个列表执行了__iter__()之后的返回值就是一个迭代器

迭代器总结:

     可以被for循环的都是可迭代的,可以迭代的内部都有__iter__方法     只要是迭代器一定可以迭代

         可迭代的类型,使用.__iter__()方法就可以得到一个迭代器 ,迭代器中的__next__方法可以一个一个的获取值 ,for 循环其实就是在使用迭代器,使用print([].__iter__())打印出的结果有:类型_iterator object at XXXXX,表示为是一个迭代器即可循环类型,

        只有是迭代对象的时候才能使用for循环,当遇到一个新的变量,不确定能不能for循环的时候,就判断它是否是迭代器   

迭代迭代器的好处:

                              从容器类型中一个一个的取值,会把所有的值都取到。 节省内存空间 迭代器并不会在内存中在占用一大块内存,

                             而是随着循环,每次生成一个,每次next一个然后给我

 

二、生成器

生成器两种类型说明

                                  1、生成器函数

                                  2、声称其表达式

1、生成器函数

   只要含有yield关键字的函数都是生成器函数,yield只能用于函数里,不可以用在函数外面,yield也和return一样可以返回一个值(不会结束代码),但是是返回的是生成器,且在同一个函数里return不可以和yield共用
1、单独获取一个生成器的值
def generator():
    print(123456789)
    yield 'a'          #yield也会将后面的值返回,但是不会结束该函数的代码

ret = generator()    #执行生成器函数:执行之后会得到一个生成器作为返回值
print(ret)
print(ret.__next__())     #使用.__next__()方法可以获取一次生成器的值

2、循环获取生成器的值
def generator():           #定义生成器函数
    print(1)
    yield 'a'
    print(2)
    yield 'b'
    print(3)
    yield 'c'
p = generator()        #接收返回值并执行生成器函数
print(p)               #打印生成器的内存地址
print(p.__next__())    #打印生成器内容到第一个yield
print(p.__next__())    #打印生成器内容到第二个yield
print(p.__next__())    #打印生成器内容到第三个yield
#下面是循环打印
for i in p:
    print(i)
说明:生成器生成的代码是每次调用现生成的,不是一次性都生成在了内存里,节省内存
def wahaha():
    for i in range(200):
        yield '易搜%s' %i
g = wahaha()
count = 0
for i in g:
    count += 1
    print(i)
    if count > 50:          #只打印50个
        break

实现一个监控用户指定文件名内容的生成器代码

def tail(filename):
    f = open(filename,encoding='utf-8')
    while True:
        line = f.readline()
        if line.strip():
            yield line.strip()
g = tail('file')
for i in g:
    if 'yisou.co' in i:          #如果文件里包含yisou.co的字符串
        print('****',i)           #就打印

send的使用

def generator():        #定义一个生成器函数
    print(123)
    p = yield 1             #返回一个生成器,并使用p接收一个值
    print('----',p)
    yield 2                    #返回第二个生成器
ret = g = generator()     #执行生成器函数,并接受生成器
print(ret.__next__())      #激活生成器
print(ret.send('hello'))     #执行生成器,并向上一个yield传一个值
send说明:
send获取下一个值得效果和next基本一致,
只是在获取下一个值的时候,给上一个yield的位置传递一个数据
使用send的注意事项:
第一次使用生成器的时候,一定要用__next__获取下一个值,否则会报错
最后一个yield不能接收外部的值

下面是一个计算平均数的生成器(使用到了send方法)

 

def average():            #定义生成器函数
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg        #返回生成器
        sum += num
        count += 1
        avg = sum/count
avg_g = average()        #调用生成器函数,并使用avg_g变量接收生成器返回值
avg_g.__next__()          #激活装饰器
avg1 = avg_g.send(10)     #使用send方法调用生成器并传一个值给上一个变量
avg2 = avg_g.send(20)     #使用send方法调用生成器并传一个值给上一个变量
print(avg1,'分割符',avg2)       #打印计算结果

yeild from使用

yeild from 实现整体返回,单个读取

def genarator():
    a = 'abcdef'
    b = '123456'
    yield from a        #yield from a 整体输出,可以实现单个读取
    yield from b

g = genarator()
for i in g:
    print(i)

2、生成器表达式

g = (i for i in range(10))       #g为生成器
print(g)            #打印生成器
for i in g:          #循环生成器
    print(i)

迭代器与生成器总结

迭代器:
可迭代协议:含有__iter__方法的都是可以迭代的,可迭代的类型都可以for循环
迭代器协议:含有__next__和__iter__方法的都是迭代器
特点:节省内存空间,方便逐个取值,一个迭代器只能取一次值

生成器:
生成器函数:含有yield关键字的函数都是生成器函数
生成器函数的特点:调用之后函数内的代码不执行,返回生成器
每从生成器中取一个值就会执行一段代码,遇见yield就停止
如何从生成器中取值:1、for :如果没有break会一直到取完
2、next :每次只获取一个值
3、send :获取值时不能第一个使用send,要使用next,send取下一个值的时候给上一个位置传一个新的值
4、数据类型强制转换 :会一次性把所有数据都读取到内存里(大数据量时不要使用)
生成器表达式:
(条件成立想放在生成器中的值 for i in 可迭代的类型 if 条件)

各种推导式

了解即可

1、列表推导式的几种写法

1print(['鸡蛋%s' %i for i in range(10)])
结果为:鸡蛋0 ... 鸡蛋9 


2print([i*2 for i in range(10)]) #结果为:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
3print([i*i for i in range(10)]) #结果为:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4、30以内所有能被3整除的数 ret = [i for i in range(30) if i%3 == 0]

5、30以内所有能被3整除的数的平方 ret = [i*i for i in range(30) if i%3 == 0]

6、找到嵌套列表中名字含有两个‘e’的所有名字 names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'], ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] print([name for lst in names for name in lst if name.count('e') >= 2])

2、字典推导式

1、将一个字典的key和value对调
mcase = {'a': 10, 'b': 34}
mcase_frequency = {mcase[k]: k for k in mcase}
print(mcase_frequency)

2、合并大小写对应的value值,将k统一成小写
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
print(mcase_frequency)

3、集合推导式

1、计算列表中每个值的平方,自带去重功能

squared = {x**2 for x in [1, -1, 2]}
print(squared)
# Output: set([1, 4])

4、练习题

1、过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
[name.upper() for name in names if len(name)>3] 

2、求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表
[(x,y) for x in range(5) if x%2==0 for y in range(5) if y %2==1]

3、求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]
[row[2] for row in M] 

生成器练习题

1、练习题1

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))          #结果[]

总结:

        生成器返回后只可以被调用一次,如果需要调用多个生成器需要依次返回多个生成器

画图说明执行步骤:

 

2、练习题2

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)
#2、拆解上面的for循环
#当n = 1时
#执行这个g=(add(n,i) for i in g)
#当n = 10时
#执行这个g=(add(n,i) for i in g)

print(list(g))     #1、从这里开始执行,结果为:20,21,22,23




#执行步骤说明:
def add(n,i): 
    return n+i 
def test():
    for i in range(4):   
        yield i     #返回生成器0,1,2,3

g = test()             #g = 0,1,2,3
for n in [1,10]:
    g=(add(n,i) for i in g)
#2、拆解上面的for循环
#当n = 1时
#执行这个g=(add(n,i) for i in g)    #3、这个g=上面的0,1,2,3
#当n = 10时
#执行这个g=(add(n,i) for i in g)    #2、执行这里g=(add(n,i) for i in (add(n,i) for i in g)),此时n=10,g=0,1,2,3;4、10+0,10+1,10+2,10+3,执行这步后为:g=(add(n,i) for i in (10,11,12,13));5、之前前面n+i,最终结果为:20,21,22,23

print(list(g))     #1、从这里开始执行

画图说明:

 

3、练习题3

def add(n,i):
    return n+i
def test():
    for i in range(4):
        yield i
g = test()
for n in [1,10,5]:
    g = (add(n,i) for i in g)
print(list(g))

结果为;15,16,17,18

执行步骤同练习2一样

posted @ 2018-08-09 13:35  欧-阳  阅读(112)  评论(0)    收藏  举报