python基础15下_迭代器_生成器

print(dir([]))   #告诉我列表拥有的所有方法
# 双下方法
# print([1].__add__([2]))
print([1]+[2])

ret = set(dir([]))&set(dir({}))&set(dir(''))&set(dir(range(10)))
print(ret)  #iterable

print('***'.center(50,'-'))
# 只要是能被for循环的数据类型 就一定拥有__iter__方法
print('__iter__' in dir(int))
print('__iter__' in dir(bool))
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)))

# Iterable  可迭代的    -- > __iter__  # 只要含有__iter__方法的都是可迭代的
# [].__iter__() 迭代器  -- > __next__  # 通过next就可以从迭代器中一个一个的取值

# 只要含有__iter__方法的都是可迭代的 —— 可迭代协议

# 迭代器的概念
# 迭代器协议 —— 内部含有__next__和__iter__方法的就是迭代器

# 迭代器协议和可迭代协议
# 可以被for循环的都是可迭代的
# 可迭代的内部都有__iter__方法
# 只要是迭代器 一定可迭代
# 可迭代的.__iter__()方法就可以得到一个迭代器
# 迭代器中的__next__()方法可以一个一个的获取值

from collections import Iterable
from collections import Iterator
print('****'.center(50,'_'))
print(isinstance([],Iterator))    # False 不是迭代器
print(isinstance([],Iterable))    # True  是可迭代的

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

 

# 生成器 —— 迭代器
# 生成器函数 —— 本质上就是我们自己写得函数
# 生成器表达式

#只要含有yield关键字的函数都是生成器函数
# yield不能和return共用且需要写在函数内
def generator():
    print(1)
    yield 'a'

# #生成器函数 : 执行之后会得到一个生成器作为返回值
ret = generator()       # 拿到生成器
print(ret)              # 打印内存地址
print(ret.__next__())   # 执行函数体,直到遇到 yield

def generator2():
    print(111)
    yield 'aaa'
    print(222)
    yield 'bbb'
    yield 'ccc'
g = generator2()
# for i in g:
#     print(i)
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)
ret = g.__next__()
print(ret)

#娃哈哈%i
def wahaha():
    for i in range(2000000):
        yield '娃哈哈%s'%i
g = wahaha()
g1 = wahaha()   # 两个独立的生成器
print(g.__next__())
print(g.__next__())
print(g1.__next__())
print(g1.__next__())


gg = wahaha()
count = 0
for i in gg:
    count +=1
    print(i)
    if count > 50:
        break

print('*******',gg.__next__())  # 生成器继续前面的往下走

for i in gg:                    # 生成器继续前面的往下走
    count +=1
    print(i)
    if count > 100:
        break

 

生成器与send方法

# 从生成器中取值的几个方法
    # next
    # for
    # 数据类型的强制转换 : 缺点:占用内存



def generator():
    print(123)
    content = yield 1
    print('=======',content)
    print(456)
    arg = yield 2
    ''''''
    yield
g1 = generator()
g2 = generator()
g1.__next__()
g2.__next__()
print('>>>>>',generator().__next__())
print('***',generator().__next__())

g = generator()
ret = g.__next__()
print('***',ret)
ret = g.send('hello')   # send的效果和next一样, 但是多了传递数据的功能
print('***',ret)

# send 获取下一个值的效果和next基本一致
# 只是在获取下一个值的时候,给上一yield的位置传递一个数据
# 使用send的注意事项
    # 第一次使用生成器的时候 是用next获取下一个值
    # 最后一个yield不能接受外部的值
def generator():
    print(123)
    content = yield 1
    print('=======', content)
    print(456)
    yield 2
    ''''''
    yield


g = generator()
ret = g.__next__()
print('+++', ret)
res = g.send('hello')  # send的效果和next一样
print('--->', res)


# send 获取下一个值的效果和next基本一致
# 只是在获取下一个值的时候,给上一yield的位置传递一个数据
# 使用send的注意事项
# 第一次使用生成器的时候 是用next获取下一个值
# 最后一个yield不能接受外部的值


# 案例应用: 获取移动平均值
# 10 20 30 10
# 10 15 20 17.5
# avg = sum/count

def avgs():
    sum = 0
    cnt = 0
    avg = 0
    while True:
        num = yield avg
        sum += num
        cnt += 1
        avg = sum / cnt


g = avgs()
g.__next__()
avg1 = g.send(10)
avg1 = g.send(8)
print(avg1)
avg2 = g.send(6)
print(avg2)

 

利用生成器来监视文件内容:

# 文件内容监视
def tail(filename):
    with open(filename,encoding='utf8') as f:
        while 1:
            line = f.readline()
            if line.strip():
                # print(line)
                yield line.strip()

g = tail('file')
for i in g:
    if 'python' in i:
        print('***',i)

 

给生成器函数加上装饰器,省掉一步 __next__()

# 预激生成器的装饰器
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)

 

直接 yield from 

def gen():
    a = 'abcdef'
    b = '12345'
    yield from a   # 直接对容器类型生成器
    yield from b


g = gen()
# for i in g:
#     print(i)

print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())

 

两个生成器的小例子:

# 3.处理文件,用户指定要查找的文件和内容,将文件中包含要查找内容的每一行都输出到屏幕
def check_file(filename, txt):
    with open(filename, encoding='utf8') as f:
        for i in f:
            if txt in i:
                yield i


g = check_file('a.txt', '正当防卫')
for i in g:
    print(i.strip())
    

# 4.写生成器,从文件中读取内容,在每一次读取到的内容之前加上‘***’之后再返回给用户。
def read_file(filename):
    with open(filename, encoding='utf-8') as f:  # 句柄 : handler,文件操作符,文件句柄
        for i in f:
            yield '***' + i


for i in read_file('a.txt'):
    print(i.strip())

 

生成器表达式遇到循环

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(g)) # 如果这里list了,则下面两个都取不到值,因为已经空了。
print(list(g1))  # list 取走了所有 g1 的值
print(list(g2))  # g2 已经空了,没有值


#### 生成器表达式 循环
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)

# 遇到上面的for循环生成器表达式,就把它拆开如下:
# n = 1
# g=(add(n,i) for i in test())
# n = 10
# g=(add(n,i) for i in (add(n,i) for i in test()))
# n = 5
# g=(add(n,i) for i in (add(n,i) for i in (add(n,i) for i in test())))
# 上面一句的结果 g=(15,16,17,18)

print(list(g))  # [15,16,17,18]

 

posted @ 2018-05-03 22:40  枫若雪  阅读(135)  评论(0编辑  收藏  举报