同学,迭代器生成器了解一下

迭代器

可迭代的

一个含有__iter__方法的对象就是可迭代的,他们都可以使用for循环取值(这样说并不对,__iter__方法应返回一个迭代器).

例如:

print('__iter__' in dir([])) # True
print('__iter__' in dir(())) # True
print('__iter__' in dir("wfdsf")) # True
print('__iter__' in dir(123)) # False

迭代器

内部含有__next__方法的可迭代对象就是迭代器 , 迭代器是可迭代的一部分.

可迭代对象调用__iter__()就形成了一个迭代器

ret = "adc".__iter__()
ret2 = ret.__iter__()
# 查看类型
print(type(ret)) # <class 'str_iterator'>
# 查看可迭代对象与迭代器之间的差集
print(set(dir("abc".__iter__()))-set(dir("abc")))
# {'__next__', '__setstate__', '__length_hint__'}
# 查看迭代器与可迭代对象的__iter__方法有什么不同
print(ret==ret2) # True
# 使用__next__方法从迭代器中取值
print(ret.__next__()) # a
print(ret.__next__()) # b
print(ret.__next__()) # c
print(ret.__next__()) # 抛出 StopIteration 异常

#利用while循环来实现for循环的功能
l = [1,2,3,4]
l_iter = l.__iter__()
while True:
    try:        #处理异常
        item = l_iter.__next__()
        print(item)
    except StopIteration:
        break

判断一个对象是不是迭代器或一个可迭代的

方式一,

判断方法__iter__是否存在于变量的方法中,存在则是可迭代的(除非你自己写了个类实现了此方法)

判断方法__next__是否存在于变量的方法中,存在则是迭代器(除非你自己写了个类实现了此方法)

print('__iter__' in dir([1,2,3,4])) # True
print('__next__' in dir([1,2,3,4])) # False

 方式二

判断对象是不是迭代器或可迭代对象的实例

from collections import Iterable # 可迭代对象的类
from collections import Iterator # 迭代器的类
print(isinstance([1,2,3,4],Iterable)) # True

str_iter = [1,2,3,4].__iter__()
print(isinstance(str_iter,Iterator)) # True

print(isinstance([1,2,3,4],Iterator)) # False

迭代器的特点

  • 惰性运算
  • 从前到后一次取值,过程不可逆,不可重复
  • 节省内存

生成器

生成器的本质就是迭代器

因此生成器具有迭代器的特点,但是生成器是我们自己写的代码

生成器函数

一个包含yield关键字的函数就是一个生成器函数。

yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

def genrator_fun1(): # 这个函数就是一个生成器函数
    yield 1
    yield 2
x=genrator_fun1()#x 就是一个生成器
print(type(x)) # <class 'generator'>
print(x.__next__()) # 1
print(x.__next__()) # 2

监听文件末尾追加的例子:

#监听文件末尾追加的例子
def tail():
    f = open('文件','r',encoding='utf-8')#打开文件
    f.seek(0,2)把光标移至末尾
    while True:
        line = f.readline()#读取内容
        if line:#内容不为空
            yield line#返回读取到的内容
        import time
        time.sleep(0.1)
g = tail()
for i in g:
    print(i.strip())

send方法

send方法可以将数据传递给生成器,并返回了一个yield值

def func():
    a = yield 5
    # send的值会由yield前的变量接收,因为表达式会先计算右边的值,后面不会执行
    # 所以说至少yield一次才能send,否则会抛出TypeError异常
    yield a

g = func()
num = g.__next__()
print(num) # 5
num2 = g.send('alex')
print(num2) # alex

第一次也可以g.send(None),相当于g.__next__()

求平均数实例

def init(func):  #生成器的预激装饰器
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)   #func = averager
        g.__next__() # 先执行一次__next__()
        return g
    return inner

@init
def averager(): # 求平均值
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average # 返回average, send传值给term
        total += term # 总和
        count += 1 # 次数
        average = total/count # 平均数

g_avg = averager()
print(g_avg.send(10))#10
print(g_avg.send(30))#20

yield form用法

def func():
    a = 'AB'
    b = 'CD'
    yield from a# 相当于for i in a:yield i
    yield from b# 相当于for i in b:yield i

# 'A','B','C','D'
# 返回了4次
g = func()
for i in g:
    print(i)

生成器表达式

#列表推导式
y = [1,2,3,4,5,6,7,8]
x = [1,4,9,16,25,36,49,64]
#由列表y要得到一个列表x
x = [i*i for i in y]#列表推导式


#生成器表达式
#把列表推导式的[]换成()就变成了生成器表达式。
l = ['鸡蛋%s'%i for i in range(10)]
print(l)#列表表达式获得一个列表
#生成器表达式获得了一个生成器
laomuji = ('鸡蛋%s'%i for i in range(10))
for egg in laomuji:
    print(egg)

面向对象中使用__iter__

for循环的本质起始就是调用一个对象的__iter__()方法,获得一个迭代器,使用__next__()方法取值,并且做了异常处理,我们自己定义类时,也可以自己是实现__iter__()方法,这样我们的对象就可以被循环了.

class For:
    def __init__(self,list):
        self.list = list
    def __iter__(self):
        for i in self.list:
            yield i

l = For([1,2,3,4,5,6])
for i in l:
    print(i)

  在form组件中就用到了这种方法,当我们循环form实例时,他的__iter__方法循环他的字段列表,并将值yield会来

posted @ 2018-05-01 22:03  瓜田月夜  阅读(148)  评论(0编辑  收藏  举报