迭代器与生成器

1.迭代器

1.1什么是迭代?

    迭代是一个重复的过程,但是每次重复都是基于上一次重复的结果而继续

1.2什么是迭代器?

    迭代器是迭代取值的工具

1.3为什么要用迭代器?(迭代器的优缺点)

优点:1.提供一种不依赖索引取值的方式,使一些没有索引的对象也可以被迭代取值

           2.更节省内存,每一次只取一个值。

缺点:1.不如索引取值那样灵活,可能无法立刻就取到需要的值

           2.取值一次性,只能往后取,无法预测值的个数

1.4如何用迭代器?

可迭代对象:内置有__iter__方法的对象都称之为可迭代对象

包括: str\ list\ tuple\ dict\ set\ 文件对象

迭代器对象:  内置既有__iter__方法又有__next__方法的对象称为迭代器对象

包括: 文件对象

因此,迭代器对象一定是可迭代对象,但是可迭代对象不一定是迭代器对象!!!

可迭代对象通过调用其内置的__iter__方法,会有一个返回值,这个返回值就是一个对应该可迭代对象的迭代器!

调用返回值中的next方法,可以进行取值!

for循环的底层原理便是用到了迭代器的原理:

1. 调用in后面那个值/对象的__iter__方法,拿到一个迭代器对象iter_obj

2. 调用迭代器对象iter_obj.__next__()将得到的返回值赋值变量名k,循环往复直到取值完毕抛出异常StopIteration

3.捕捉异常结束循环

迭代器练习:

#利用迭代器的原理,取出字典中的值
d={'k1':111,'k2':222,'k3':333}  #d是一个可迭代对象
iter_d=d.__iter__() #iter_d是一个迭代器
while True:
    try:
        v=iter_d.__next__()
        print(v)
    except StopIteration:
        break

###当我迭代取完值后,我再去值的时候就会因为取不到值而报错,这个时候我们可以用try--###---except机制,捕捉异常,是代码不报错,正常走下去!
View Code

2.生成器

2.1定义:生成器就是一种自定义的迭代器

2.2如何得到生成器?

    但凡函数内出现yiled关键字,调用函数执行到yiled关键字处时暂停函数执行,会得到一个跟在yiled后面的返回值,该返回值就是生成器对象,即自定义的迭代器。

    注意:得到的是一个生产器对象哦,并不是一个普通的值

def func():
    print('first')
    yield 1
    print('second')
    yield 2
    print('third')
    yield 3


g=func()
print(g)


#输出为<generator object func at 0x0000021B70E557D8>

#需要在代码后写上next(g)才能把值输出来

2.3 yield关键字提供一种自定义迭代器的解决方案

     yield & return

      相同点:都可以返回值,返回值没有类型限制\个数限制

      不同点:return 只能返回一次值,yield却可以让函数暂时在某一个位置停留,下一次再调用

                    next 的时候从上次暂停的位置继续往下执行,可以返回多次值

小练习:利用生成器做一个自定义的随机数取值函数,限定范围和步长取值

def my_range(start,end,step):
    while start <end:
        yield start
        start+=step

res=my_range(1,5,3)
while True:
    try:
        print(next(res))
    except StopIteration:
        break
View Code

3.递归函数

定义:再调用一个函数的过程又直接或者间接地调用该函数本身,称之为递归调用

递归必须满足两个条件:1.每进入下一次递归调用,问题的规模都应该有所减少

                                       2.递归必须有一个明确的结束条件

递归有两个明确的阶段:1.回溯  2.递推

回溯是指一个函数在其内部又调用了它这个函数(参数可以不同),减小其规模,进入到了一个循环的过程。

递推指的是在回溯到一个阶段,最后的函数满足一定的条件时,最后一个函数结束执行,然后往前返回,函数结束执行的过程。

小练习:利用递归函数,将列表中所有数字输出来

def func(list1):
    for item in list1:
        if type(item) is not list:
            print(item)
        else:
            func(item)
l=[1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]]
func(l)
View Code

 

4.二分法

取对象的中间值,与要寻找的值进行比较,然后进行切片,继续这个过程,直到找到这个值为止(或者直到对象中只有一个值还没有找到需要的值,那么对象中没有需要的值)

def two_fen(num,list1):
    mid_index=len(list1)//2
    if len(list1)==0:
        print('列表中没有这个值')
        return
    if num>list1[mid_index]:
        return two_fen(num,list1[mid_index+1:])
    elif num<list1[mid_index]:
        return two_fen(num,list1[:mid_index])
    else:
        return num
nums=[3,5,7,11,13,23,24,76,103,111,201,202,250,303,341]
res=two_fen(24,nums)
print(res)
View Code

了解知识点:

在上述代码中,如果在使用递归函数时直接使用two_fen(num,list1[mid_index+1:]),这种方法而没有用retuen 时,

这个递归函数最终是没有返回值的。这个知识点在博客Python 递归函数返回值为None的解决办法中有详解。

 

posted on 2018-12-03 16:20  黑粥  阅读(134)  评论(0编辑  收藏  举报

导航