第八章 迭代器&生成器

一、迭代器
迭代是Python最强大的功能之一,是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象
迭代器对象从集合的第一个元素开始访问,知道所有的元素访问完结束。迭代器只能往前不会后退
迭代器有两个基本的方法:__item__()和__next__()
1. dir ()
用来查看数据类型的数据能够执行那些方法,而得到所有的带'__iter__'可以使用for循环,就是可迭代对象
print(dir(str))
E:Anacondapython.exe F:/老男孩python/作业训练/8.10/Train.py
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', 
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', 
'__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', 
'__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
'__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', 
'__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 
'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 
'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 
'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 
'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 
'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

Process finished with exit code 0
2. __next__()
可迭代对象可以使用__iter__()来获取到迭代器,而在迭代器中有__next__()
s = "这是一个可迭代对象"
it = s.__iter__()   # 获取迭代器
print(dir(it))  # 迭代器里有__iter__ 还有__next__
E:Anacondapython.exe F:/作业训练/8.10/Train.py
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__',
'
__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__',
'__subclasshook__'] Process finished with exit code 0
3.特点:
- 只能向前
只能向下一步进行,不能将之前的结果重新获取
- 几乎不占用内存
只有需要的时候,他才给出运行
- for循环
# 迭代器模拟for 循环
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
for el in lst:  # 底层用的就是迭代器
    print(el)
    
it = lst.__iter__() # 获取迭代器
while 1:
    try:    # 尝试执行
        el = it.__next__()  # 获取下一个元素
        print(el)
    except StopIteration:   # 处理错误
        break    # 当执行到最后的时候跳出
- 惰性机制
每执行一次'__next()',才给出一个结果,不执行就不给
s = "这是一个可迭代对象"
it = s.__iter__()   # 获取迭代器
print(it.__next__())    # "这"
print(it.__next__())    # "是"
print(it.__next__())    # "一"
print(it.__next__())    # "个"
print(it.__next__())    # "可"
print(it.__next__())    # "迭"
print(it.__next__())    # "代"
print(it.__next__())    # "对"
print(it.__next__())    # "像"
print(it.__next__())    # 超出了迭代范围会报错    "print(it.__next__())  StopIteration"
4. 如何判断
from collections import Iterable # 可迭代对象
from collections import Iterator # 迭代器

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
it = lst.__iter__() # 获取迭代器
print(isinstance(lst, Iterable))    # True 为可迭代对象
print(isinstance(lst, Iterator))    # False 不为迭代器
print(isinstance(it, Iterable))     # True
print(isinstance(it, Iterable))     # True

# 偏方
print("__iter__" in dir(it))    # T
print("__n__" in dir(it))    # F
5. list()
list(参数)把参数进行循环迭代
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
it = lst.__iter__()
s = list(it)
print(s)    # [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
此处的list如果问set 则输出的就是一个集合,其他如tuple等相同
 
我们可以把要迭代的内容当成子弹,然后呢获取到迭代器"__iter__()",就把子弹都装在弹夹中,然后发射就是“__next__”把每一个子弹(元素)打出来,也就是说:for 循环的时候,一开始的时候是"__"来
获取迭代器,后面每次获取元素都是通过"__next__()"来完成的,当程序遇到Stoplteration将结束循环.
二、生成器
生成器的本质就是迭代器
在Python中,使用了yield的函数被称为生成器(generatoor)
生成器一般由生成器函数或者生成器表达式来创建
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单理解生成器就是一个迭代器
在调用生成器允许的过程中,每次遇到 yield 时函数会暂时保存当前所有的运行信息,返回 yiled 的值,并在下一次执行next()方法时从当前的位置继续运行
调用一个生成器函数,默认不会执行函数体,返回的是一个迭代器对象
def func():
    print("哇哈哈")
    yield 1 # return和yiled都能返回数据
    print("呵呵呵")

gen = func()

# 函数中如果有yield 这个函数就是生成器函数,生成器函数生成的是生成器,这个时候不执行函数
# yield:相当于return可以返回数据,但是yield不会彻底中断函数。分段执行
gen.__next__()  # 执行函数,执行到下一个yield
gen.__next__()  # 继续执行到下一个yield 如果没有则会报错    gen.__next__() StopIteration
1. 生成器的作用
举例需求:
当商店需要1W套学士服以备后面的使用:
def cloth():
    lst = []
    for i in range(0, 10000):
        lst.append("衣服"+str(i))
    return lst
cl = cloth()
这样的结果是生产商一次将1W套学士服都给商家,商家不一次性全部卖出的话就会堆积仓库,最好的方式就是商家要一套,生产商给一套,一共1W套:
def cloth():
    for i in range(0, 10000):
        yield "衣服"+(i)
cl = cloth()
print(cl.__next__())
print(cl.__next__())
print(cl.__next__())
区别是:第一种是直接一次性全部拿出来,会很占内存。第二种使用生成器,一次就用一个。用多少生成多少,生成器是一个一个的指向下一个。不会回去,__next__()到哪里,指针就指到哪里.下一次继续获取指针指向的值.
由此我们可以反应出生成器的那几个特点:
- 惰性机制
- 节省内存
- 只能向前
2. send()函数
同__next__()一样都可以让生成器执行到下一个yied。
# send 函数
def num():
    print("1")
    a = yield "2"
    print("a=", a)
    b = yield "3"
    print("b = ", b)
    c = yield "4"
    print("c = ", c)
    yield "END"
gen = num()     # 获取生成器
ret1 = gen.__next__()
print(ret1)
ret2 = gen.send("5")
print(ret2)
ret3 = gen.send("6")
print(ret3)
ret4 = gen.send("7")
print(ret4)

E:Anacondapython.exe F:/训练/8.13/Train.py
1
2
a= 5
3
b =  6
4
c =  7
END
send和__next__()区别:
- send和__next__()都是让生成器向下走一次
- send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器代码的时候哦不能使用send()
3. 循环:
生成器可以使用for循环来循环获取内部的元素:
def func():
    print("1")
    yield "2"
    print("3")
    yield "4"
    print("5")
    yield "6"
    print("7")
    yield "8"

gen = func()
for i in gen:
    print(i)
 
原文地址:https://www.cnblogs.com/jiumo/p/9457582.html