python 函数的应用之迭代器、生成器

一 迭代器
双下方法 : 很少直接调用的方法。一般情况下,是通过其他语法触发的
可迭代的 —— 可迭代协议 含有__iter__的方法('__iter__' in dir(数据))
可迭代的一定可以被for循环
迭代器协议: 含有__iter__和__next__方法
迭代器一定可迭代,可迭代的通过调用iter()方法就能得到一个迭代器
迭代器的好处:
# 从容器类型中一个一个的取值,且只能取所有的数据取一次
    # 节省内存空间
--迭代器并不会在内存中再占用一大块内存,
而是随着循环 每次生成一个
每次next每次给我一个
  
迭代器的用法
#iterator = l.__iter__()
#iterator.__next__()

# for i in l:
# pass

 直接给内存地址
print([].__iter__()) 
# <list_iterator object at 0x003A5D70>
print(range(10))     # range(0, 10)
for
#只有 是可迭代对象的时候 才能用for
# for循环其实就是在使用迭代器
#当我们遇到一个新的变量,不确定能不能for循环的时候,就判断它是否可迭代
#判断是否可迭代
print
('__iter__' in dir(int)) False print('__iter__' in dir(bool)) False print('__iter__' in dir(str)) True print('__iter__' in dir(list)) print('__iter__' in dir(dict)) print('__iter__' in dir(set)) print('__iter__' in dir(tuple)) print('__iter__' in dir(enumerate([]))) print('__iter__' in dir(range(1))) #只有前两个False
dir([])
print(dir([]))   #列表拥有的所有方法
print(dir([].__iter__())) print(set(dir([].__iter__())) - set(dir([]))) #{'__next__', '__setstate__', '__length_hint__'}
print(['a','bbb'].__iter__().__length_hint__())  #元素个数

二 生成器 —— 迭代器
生成器的本质就是迭代器
生成器的表现形式
生成器函数
生成器表达式
生成器函数:
含有yield关键字的函数就是生成器函数
特点:
调用函数的之后函数不执行,返回一个生成器
每次调用next方法的时候会取到一个值
直到取完最后一个,在执行next会报错
def generator():
    print(1)
    yield 'a'
#生成器函数 : 执行之后会得到一个生成器作为返回值
ret = generator()
print(ret) # <generator object generator at 0x0058DB40>
print(ret.__next__()) # 1 a
def wahaha():
    for i in range(2000000):
        yield '娃哈哈%s'%i
g = wahaha()
g1 = wahaha()
print(g.__next__())    # 娃哈哈0
print(g1.__next__())   # 娃哈哈1
print(g1.__next__())   # 娃哈哈0
print(g1.__next__())   # 娃哈哈1

g = wahaha()
count = 0
for i in g:
    count +=1
    print(i)
    if count > 50:                                
        break
print('*******',g.__next__())
for i in g:
    count +=1
    print(i)
    if count > 100:
        break

     

    从生成器中取值的几个方法

    # next
# for
# 数据类型的强制转换 : 占用内存
g = generator()  #调用生成器函数得到一个生成器
print(list(g))

    

send 获取下一个值的效果和next基本一致
只是在获取下一个值的时候,给上一yield的位置传递一个数据
使用send的注意事项
第一次使用生成器的时候 必须用next获取第一个值
最后一个yield接受外部不到的值
def averager():
    average = None
    sum = 0
    count = 0
    while True:
        num = yield average
        count+=1
        sum += num
        average = sum/count
f = averager()
f.__next__()
print(f.send(10))
print(f.send(20))
print(f.send(30))
示例
预激生成器的装饰器
def init(func):   #装饰器
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)    #g = average()
        g.__next__()
        return g
    return inner

@init
def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg
        sum += num    # 10
        count += 1    # 1
        avg = sum/count

avg_g = average()   #===> inner
ret = avg_g.send(10)
print(ret)
ret = avg_g.send(20)
print(ret)
预激生成器的装饰器

python3 ------- (yield from 容器型元素)的用法

def generator():
    a = 'abcde'
    b = '12345'
    for i in a:
        yield i
    for i in b:
        yield i
# def generator():
#     a = 'abcde'
#     b = '12345'
#     yield from a  
#     yield from b
#
g = generator()
for i in g:
    print(i)
示例

 三  生成器推导式

#生成器函数
def init(func):  #在调用被装饰生成器函数的时候首先用next激活生成器
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)
        next(g)
        return g
    return inner

@init
def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total/count
g_avg = averager()
# next(g_avg)   在装饰器中执行了next方法
print(g_avg.send(10))
print(g_avg.send(30))
print(g_avg.send(5))
#生成器表达式


laomuji=('鸡蛋%s' %i for i in range(10))#生成器表达式
print(laomuji)
print(next(laomuji)) #next本质就是调用__next__
print(laomuji.__next__())
print(next(laomuji))
View Code


原文地址:https://www.cnblogs.com/olivia2018/p/8179007.html