python学习day25笔记

迭代器

什么是迭代器

迭代器就是用来迭代取值的工具

什么是迭代

迭代就是一个重复的过程,但是每次重复都是基于上一次的结果进行的

# 单纯的重复不叫迭代
n = 0
while True:
    n += 1
    
# 下面才是迭代的过程
n = 0
while n < 5:
    print(n)
    n += 1

为何要用迭代器

迭代器的优点:
    1.通用的迭代取值方案-->for循环
    2.惰性计算,节省内存
    # 惰性计算:不含有值,被需要时生成值
    
迭代器的缺点:
    1.不能取指定的值,只能通过next往下取值
    2.迭代器对象是一次性的:一个迭代器对象值取干净了就不能继续取了

如何用迭代器

粗略的使用迭代器

可迭代对象

内置有__iter__方法的对象都是可迭代对象

参数.__iter__()

通过此方法可以将参数转换为迭代器对象

迭代器对象

内置有__next__方法的对象都是迭代器对象

x = 可迭代对象.__iter__()
x.__next__()

迭代器每次运行都只按照顺序取出可迭代对象的一个值

实际上此时如果y = x.__next__(),会发现,y的可使用内置函数里也有y.__iter__(),迭代器对象同样也是可迭代对象,这个具体原因涉及到非常使用的内置循环函数for循环如何实现

带有__函数的正确使用方法

带有__的内置方法都不是给人用的
例如:需要查看'abcdefg'的长度,使用方法len('abcdefg'),实际上使用的方法是'abcdefg'.__len__()
 
所以可以将__iter__方法变成iter(),__next__方法变成next()

如何基础实现for循环

l = ['egon','jason','jack','tom','milu',]
# 将l列表内容系数打印

推导过程1

l_names = iter(l)
next(l_names)
next(l_names)
next(l_names)
next(l_names)
next(l_names)
next(l_names)

当迭代次数多于列表内容时,python会报出提示StopIteration
同时写了太多重复代码,有冗余

推导过程2

l_names = iter(l)
while True:
    try:
        print(next(l_names))
    except StopIteration
        break

结论

for循环工作原理类似如上代码
for i in l:
    print(i)
    
1.调用l的__iter__方法,得到一个迭代器对象iter_l
2.x=next(iter_l),然后运行循环体代码
3.重复步骤2,直到取完值,抛出异常,for循环会自动捕捉异常结束循环

拓展

文件不仅是可迭代对象,同时也是迭代器对象,主要是因为文件通常过于庞大,在py开发初期考虑到了这个问题,如果在程序内打开文件内容,会直接将内存撑爆,所以直接将其导入时变成迭代器对象,减少计算机负担

既然文件是迭代器对象,那么在for循环中是否有必要添加一个判断,判断目标内容是否是迭代器对象,如果是则不用运行iter()代码?
没有必要,这是明显的代码冗余,py开发时直接将iter(迭代器)=迭代器,就可以省下这步操作,使for循环代码更加精简

生产器(自定义迭代器对象)

yield

yield 对比 return
相同点:都可以返回任意类型、任意个数的值
不同点:return只能返回值一次,函数立即结束
	  yield可以返回多次值,返回值时暂停函数的运行,下一次调用函数时从暂停处继续运行
    
def func():
    print('1')
    yield 0
    print('2')
    yield 5
    print('3')
    yield 10
    
函数内但凡出现yield关键字,哪怕是没有运行到,调用函数时就不会立即执行函数体代码,而是会返回一个生成器对象
生成器对象本质就是自定义的迭代器,需要时yield返回值同时暂停函数,下一次再调用函数从暂停处继续运行
函数内出现yield,此时函数并不是生成器对象,需要调用函数后才会得到生成器对象

如何使用生成器

如何使用迭代器就如何使用生成器,在next生成器对象后,函数才会开始执行代码,直到出现yield关键字后暂停运行,并返回yield的值

# 生成器的简单使用
def func():
    res = 0
    while True:
        yield res
        res += 1
g = func()
for i in g:
    print(i)
# 无限打印在上一个数的基础上增加1的值

生成器用途

购物软件
在购物时页面不会直接生成全部的商品,在用户需要时才一个一个输出,发挥生成器惰性运算的优点

函数递归

什么是函数递归

函数递归是函数嵌套调用的一种特殊格式
即在调用一个函数时,在其内部又调用了自己

# python中不会允许无限死循环的函数递归
def foo():
    print('hello world!')
    foo()
foo()
# 函数在运行时会持续运行到出现return或者函数末尾,以上代码在运行到foo()时

函数的递归应该分为两个阶段
1.回溯:一层一层往下调用
2.递推:一层一层向上推出结果

为何要用函数递归

函数递归提供了一种基于函数实现的新的循环机制

如何用函数递归

例子1:

l = [11,[22,[33,[44,[55,[66,[77,[88]]]]]]]]

# 需求:将列表l内的所有值遍历出来
for item in l:
    if type(item) is list:
        pass  # 将此处再次运行整行代码,进行无限套娃
    else:
        print(item)
        
# 修改后
def func(i):
    for item in i:
        if type(item) is list:
            func(item)
        else:
            print(item)
func(l)

例子2:递归实现二分法

# 需求:以可控的效率在数据中查找到需要找到的值
二分法:从数据的中间开始查找,同时进行判断需要的值与当前值的大小,再向需要的值的方向继续从中间开始查找,循环往复
nums = [1,5,8,16,42,66,74,88,90,99]

def search(nums,find_num):
    if len(nums) == 0:
        print('not find')
        return
    mid = len(nums)//2
    if find_num > nums[mid]:
        search(nums[mid+1:],find_num)
    elif finde_num < nums[mid]:
        search(nums[:mid],find_num)
    else:
        print('find it')

拓展知识

三元表达式

x = 10
y = 20
res = x if x > y else y
条件成立返回x,条件不成立返回y
大概流程:条件成立返回的值 if 条件 else 条件不成立返回的值

列表生成式

l = []
for i in rango(10):
    if i > 3:
        l.append(i)

l = [i for i in range(10)]
将i遍历range(10),将每个i放进l列表
大概流程:需要放进列表的值 for循环

l = [i for i in range(10) if i > 3]
将i遍历range(10),每次运行for循环进行if判断,成立后将每个i放进l列表
大概流程:需要放进列表的值 for循环 if条件
最多只能添加if判断,不能再添加else

字典生成式(不常用)

了解即可
{'k%s'%i:i for i in range(3)}
将i遍历range(3),将每个i放进字典

集合生成式同理
{i for i in range(3)}
将i遍历range(3),将每个i放进集合

sum

sum(可迭代对象)
sum可以将里面的值全部加在一起
print(sum([1,2,3,4]))  # 输出10

生成器表达式

res = (i for i in range(10))
res是一个生成器,运行时它不会产生任何值,只有在你需要它时才会依次生成值
例如:next(res),sum(res)
    
例子:
# 需求:数出文件内有多少个值
with open('a.txt',mode='rt',encoding='utf-8')as f:
    res = sum((len(i) for i in f))
    print(res)
上一篇:用8个命令调试Kubernetes集群


下一篇:Day25_20180602_网站日志流量分析项目06:数据分析的实现及任务调度框架