10.迭代器与生成器

2019-12-21  本文已影响0人  哈哈大圣

一、迭代器

1). 迭代器概述

  1. 类比Java中的迭代器,参考迭代器模式https://www.jianshu.com/p/ee999431fb92
  2. 被迭代对象对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个Stoplteration异常,以终止迭代
  3. 迭代只能向前。
  4. 可迭代对象:实现了迭代器的对象(调用内部定义一个iter()方法,实现迭代器功能,创造迭代器对象) (类比Java中的接口)
  5. 字符串、列表、元组、字典、集合、文件对象这些不是可迭代对象,但使用for遍历的时候调用了他们内部的iter方法生成了迭代器。
  6. 使用转换str(t),list(),int(),tuple(),dict(),set()等也使用迭代器

2). 迭代器使用

  1. 判断一个对象是否可迭代
from collections import Iterable
a = isinstance("", Iterable)
b = isinstance({}, Iterable)
c = isinstance([], Iterable)
d = isinstance((), Iterable)

# True
  1. 生成迭代器
a = "abc".__iter__()
# 或者
b = iter("abc")
  1. 判断一个对象是否为一个迭代器
from collections import Iterator

# 调用iter()方法将可迭代对象转换成迭代器
a = isinstance("abc".__iter__(), Iterator)  
  1. 迭代器使用常用方法 (假设t为迭代器)

    • t.__next__(): 返回下一个迭代元素
    • next(t): 同理,返回下一个迭代元素
    • t.send("****"):配合函数中的yield使用
  2. for循环的原理

l = [1, 2, 3]
for i in l:
    print(i)

# 内部实现如下
iter_test = l.__iter__() # iter_test = iter(l)
print(iter_test)
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__()) # 这里就抛出异常
  1. 文件句柄中使用迭代器
with open('test.txt', 'r+') as f:
    for i in f:
        print(i, end="") # end参数表示打印结束为换行符

使用for遍历文件,可以减少不必要的内存空间占有率

n = "hahadasheng"
b = dir(n)
print(b)

二、生成器

1). 概述

  1. 生成器(generator object):动态生成下一个元素,按需生产。
  2. 直接使用object._next_(),无需调用__iter__()方法
  3. 生成器就是可迭代对象,延迟计算,一次返回一个结果(利于大数据处理)
  4. 一个生成器只能遍历一次,生成器在产生的时候只是返回生成器地址,当遍历的时候调用_next_()方法,位置才发生变化

2). 生成器的一般使用

  1. 列表生成式:range函数,动态生成数据
for i in range(0, 101):
    print(i)
  1. 函数生成器:生成斐波那契数列
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:  # 计算n次
        yield b     # 将函数的执行过程冻结在这一步,并且将b的值返回给next(),相当于return
        a, b = b, a + b
        n += 1
    return "done"

# 这时函数并没有执行,而是返回了一个生成器,注意:不需要使用f.__iter()__; 
f = fib(15)  
for i in f:  # f.__next__() 也是可以的
    print(i)
  1. 函数生成器:向函数中传值
    • send的作用: 唤醒并执行、发送一个信息到生成器内部(默认发送None,可以在函数内部根据传送的信号确定执行状态,比如用if进行判断是否终止)
    • next(?)?.__next__()?.send(?):这三个都能唤醒生成器继续工作。
def test():
    print("run 1")
    x = yield 1
    print(x)
    yield 2

g = test()           # 获得生成器
a = g.__next__()     # 生成器开始执行 到yield 1并挂起,并将1返回
print(a)
b = g.send("haha")   # 将值传递给x;同时获得穿回来的值
print(b)
  1. 案例:用函数实现range功能
def range2(n):
    count = 0
    while count < n:
        print("func: %s" % count)
        print(count)
        count += 1
        sign = yield count  # 返回数据count,中断程序,当外部调用next(),继续执行函数有了yield加括号,
        print("---sign",sign)  # 就成了一个生成器,如果有并执行到return 在生成器中,代表生成器的终止,直接走到报错
        
new_range = range2(10) #产生了一个生成器 print(new_range)
new_range.__next__()
new_range.__next__() #next唤醒并继续执行,相当于给生成器发送了一个None
new_range.send("stop")

3). 三元表达式

  1. 语法
结果 = value1 if 条件成立就返回value1,如果不成立就返回value2 else value2
  1. 案例
name='晓庆'
res = '女神' if name == '晓庆' else '不是女神'
print(res)
  1. 生成器-三元表达式:写到列表和元组里面,按需生产
a = [i if i % 2 == 0 else None for i in range(10)]
print(a) # [0, None, 2, None, 4, None, 6, None, 8, None]

4). 列表解析 (直接动态生成列表)

l1 = ['鸡蛋%s' %i for i in range(10)]  #二元
# ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']

l2 = ['鸡蛋%s' %i for i in range(10) if i > 5 ] #三元 生成一个列表
# ['鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']

# 没有四元表达式
# l3 = ['鸡蛋%s' %i for i in range(10) if i > 5 else i]  

5). map、sum、min、max迭代器

l = [1, 2, 3, 3, 4]
s = map(lambda x: x**x, l)
print(sum(s))


print(sum(i for i in range(1000)))

6). 生成器 + lambda + 函数闭包 + 延迟执行

import copy
def a():
    # 闭包延迟, 返回的为4个匿名函数,但是在执行时i都为3
    a, b, c, d = [lambda x: copy.copy(i) * x for i in range(4)]
    print(a(2), b(2), c(2), d(2)) # 6 6 6 6
    
    # 设定局部变量,匿名函数中的i分别为 0 1 2 3
    e, f, g, h = [lambda x, i = i: copy.copy(i) * x for i in range(4)]
    print(e(2), f(2), g(2), h(2)) # 0 2 4 6

    # 这里返回的也为延迟,i 统统为 3
    return [lambda x:copy.copy(i) * x for i in range(4)]

print([m(2) for m in a()])

上一篇下一篇

猜你喜欢

热点阅读