python全栈闯关--13-迭代器和生成器

 1、迭代器

可迭代协议

  含有双下划线方法__iter__()方法的都是可迭代

迭代器协议

  内部含有__next__和__iter__方法的就是迭代器

 

# 判断是否函数__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)))

 

print([])
print([].__iter__())  # 使用__iter__方法后,返回值为一个迭代器
print(set(dir([].__iter__())) - set(dir([])))  # {'__setstate__', '__length_hint__', '__next__'}
print([1, 2, 'aas', 'a'].__iter__().__length_hint__())  # 返回元素的个数

# 迭代器使用next方法,可以遍历值
l = [1, 2, 3, 4]
iterator = l.__iter__()
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())  # 迭代器返回值完毕后,程序报错“StopIteration”

 

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

 

迭代器协议和可迭代协议

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

 

迭代器的好处

  • 从容器中可以一个一个的取值,能取到所有值
  • 节省空间
    •   迭代器不会因此在内存中开辟一大块空间,而是随着循环,每次通过next方法,生成一个值
print(range(100000000000000))
print(list(range(1000000000)))

运行上述代码,可以看到,第一个迭代器的时候,很快就返回了结果  range(0, 100000000000000)

第二段代码,机子跑死机了,都无法正常运行

 

2、生成器函数

含有yiled关键字的函数都是生成器函数

#正常函数
def generaor():
    print('1')
    return 'a'

ret=generaor()
print(ret)

 

 

还有yiled关键字时,不能含有return关键字

def generaor():
    print('1')
    yield 'a'  # 替换return关键字未yield关键字后,就是一个生成器

ret=generaor()
print(ret)

 

 

def generaor():
    print('1')
    yield 'a'  # 替换return关键字未yield关键字后,就是一个生成器

ret=generaor()
print(ret)
print("next get value:", ret.__next__())  # 生成器使用next函数获取值

 

 生成器中,使用双下线方法来获取返回值

 

 

含有多个yield时,每次使用__next__都是到yield时,停止执行,返回值。

单生成器中的值返回完毕时,报错StopIteration

def generaor():
    print('1')
    yield 'a'  # 替换return关键字未yield关键字后,就是一个生成器
    print('2')
    yield 'b'
    yield 'c'

ret=generaor()
print(ret)
print("next get value:", ret.__next__())  # 生成器使用next函数获取值
# 1
# next get value: a

print("next get value:", ret.__next__())  # 生成器使用next函数获取值
# 2
# next get value: b

print("next get value:", ret.__next__())  # 生成器使用next函数获取值
# next get value: c
#
print("next get value:", ret.__next__())  # 生成器使用next函数获取值
# 报错StopIteration,生成器到达最后的值报错

 

同时定义多个生成器时,多个生成器间并不矛盾,每个都能获取各自独立的值

def bear():
    for i in range(20000):
        yield "bear %s" % i

g = bear()
g2 = bear()

print('生成器函数1:%s' % g.__next__())
print('生成器函数1:%s' % g.__next__())
print('生成器函数2:%s' % g2.__next__())
print('生成器函数2:%s' % g2.__next__())
print('生成器函数1:%s' % g.__next__())

 

总结:

迭代器:

  • 双下方法:很少直接调用的方法,一般情况下,通过其他语法触发;
  • 可迭代的:可迭代协议,含有__iter__方法('__iter__' in dir(类型))
  •   可迭代的一定可以被for循环;
  • 迭代器协议:含有__iter__和__next__的方法。
  •   迭代器一定可以迭代,可迭代的通过__iter__方法可以得到一个迭代器
  • 迭代器的特点:
  •   可以方便的遍历,且每个元素之使用一次;
  •   节省内存;

生成器:

生成器的本质是一个迭代器

  • 生成器函数:
  • 含有yield关键字的函数就是生成器:
  • 特点
    • 调用函数,并不会立即执行,返回一个生成器
    • 每次调用,使用__next__获取一个值
    • 直到取完最后一个值,报错

从生成器中取数的几个方法:

  •   for
  •   __next__
  •   数据类型强制转换,暂用内存

 

练习:

def tail(filename):
    with open(filename) as f:
        while True:
            line = f.readline()
            line = line.strip()
            if line:
                yield line

res = tail('file')
for line in res:
    if 'bear' in line:
        print('***', line)

 

def generator():
    for i in range(2000000000):
        yield "hello, bear %s" % i

g = generator()
print(g.__next__())
n = 0
for content in g:
    n += 1
    if n > 50:
        break
    print(content)

 

posted @ 2019-10-24 15:33  熊熊闯深林  阅读(175)  评论(0编辑  收藏  举报