zoukankan      html  css  js  c++  java
  • 第六章 Python之迭代器与生成器

    迭代器

      迭代:迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果是下一次重复的初始值

    l=['a','b','c']
    count=0
    while count < len(l):
        print(l[count])
        count+=1

      迭代器:迭代器即迭代的工具,它的作用是无论对于序列类型(如str,list,tuple),还是对于非序列类型(如dict,set,文件)等,都能获取其中的值

      可迭代对象:内置有obj.__iter__方法的对象

      迭代器对象:既内置有obj.__iter__方法,又内置有obj.__next__方法的对象,可迭代对象执行obj.__iter__方法后得到的就是迭代器对象

    #可迭代的对象,obj.__iter__
    l=[1,2,3]
    t=(1,2,3)
    d={'name':'luoli','age':18,'sex':'female'}
    s={'a','b','c'}
    f=open('user.txt','r',encoding='utf-8')
    l.__iter__()
    t.__iter__()
    d.__iter__()
    s.__iter__()
    f.__iter__()
    #迭代器对象:既有obj.__iter__,又有obj.__next__方法
    f.__next__()

      可迭代对象不一定是迭代器对象,迭代器对象一定是可迭代的对象;可迭代对象调用obj.__iter__方法得到的是迭代器对象,迭代器对象调用obj.__iter__方法得到的是本身

    d={'name':'luoli','age':18,'sex':'female'}
    d_iter=d.__iter__()
    print(d_iter.__next__())
    print(d_iter.__next__())
    print(d_iter.__next__())
    print(d_iter.__next__()) #迭代器取值完毕抛出异常

      for循环详解

    #调用in后的对象的iter方法,使其成为一个迭代器:obj_iter=obi.__iter__--->调用next方法获取值:k=obj_iter.__next__()--->捕捉异常,结束迭代
    d={'name':'luoli','age':18,'sex':'female'}
    for k in d:
        print(k)
    
    d={'name':'luoli','age':18,'sex':'female'}
    d_iter=iter(d)
    while True:
        try:
            print(next(d_iter))
        except StopIteration:
            break

      迭代器优点:提供了一种统一的,不依赖于索引的取值方式,为for循环的实现提供了依据;更节省内存

      缺点:只能往后并且一次性的取值;不能使用len()方法

    生成器

      只要函数内部包括yield关键字,那么函数名()得到的结果就是生成器,并且不会执行函数内部代码

      生成器就是迭代器,yield提供了一种自定义迭代器的方法

      yield与return的区别:yield可以返回多次值;函数暂停与继续的状态由yield保存

    def func():
        print('--1')
        yield 1
        print('--2')
        yield  2
        print('--3')
        yield 3
    
    #调用生成器函数将返回一个生成器
    g=func()
    #第一次调用生成器的next方法时,生成器才开始执行生成器函数(而不是构建生成器时),直到遇到yield时暂停执行(挂起),并且yield的参数将作为此次next方法的返回值
    next(g)
    #之后每次调用生成器的next方法,生成器将从上次暂停执行的位置恢复执行生成器函数,直到再次遇到yield时暂停,并且同样的,yield的参数将作为next方法的返回值
    next(g)
    next(g)
    #如果当调用next方法时生成器函数结束(遇到空的return语句或是到达函数末尾),则这次next方法的调用将抛出StopIteration异常(即for循环终止的条件)
    next(g)

      yield表达式形式的用法

    def eater(name):
        print('%s ready to eat'%name)
        food_list=[]
        while True:
            food=yield food_list #food=yield=banana
            food_list.append(food)
            print('%s start eat to eat %s'%(name,food))
            print(food_list)
    
    e=eater('luoli')
    #首先要初始化
    next(e) #e.send(None)
    #然后传值e.send()从暂停的位置将值传给yield,然后功能与next一样
    e.send('banana')
    e.send('peach')

    练习

      (1)自定义函数模拟range()

    def my_range(start,stop,step=1):
        while start < stop:
            yield start
            start+=step
    
    g=my_range(1,500,2)
    print(next(g))
    print(next(g))
    print(next(g))

      (2)模拟管道,实现功能:tail -f access.log | grep '404'

    import time
    def tail(filepath):
        with open(filepath,'rb') as f:
            f.seek(0,2)
            while True:
                line=f.readline()
                if line:
                    yield line
                else:
                    time.sleep(2)
                    print('run')
    
    
    def grep(lines,pattern):
        for line in lines:
            line=line.decode('utf-8')
            if pattern in line:
                yield line
    
    lines=grep(tail('access.log'),'404')
    for line in lines:
        print (line)

    三元表达式

    def my_max(x,y):
        if x>y:
            return x
        else:
            return y
    
    x=20
    y=30
    res=x if x>y else y

    列表推导式

    l=['egg'+str(i) for i in range(1,11) if i>=6]
    print(l)

    生成器表达式

    g=('egg'+str(i) for i in range(1,1000000000000))
    print(g)
    print(next(g))
    print(next(g))
    print(next(g))
    # 练习
    # 将names=['egon','alex_sb','wupeiqi','yuanhao']中的名字全部变大写
    names=['egon','alex_sb','wupeiqi','yuanhao']
    names=[name.upper() for name in names]
    print(names)
    
    # 将names中以sb结尾的名字过滤掉,然后保存剩下的名字长度
    names=[name for name in names if name.endswith('sb')]
    print(names)
    
    # 求文件a.txt中最长的行的长度(长度按字符个数算,需要使用max函数)
    with open('a.txt','r',encoding='utf-8') as f:
        # l=[]
        # for line in f:
        #     #print(len(line))
        #     l.append(len(line))
        res=max(len(line) for line in f)
        print(res)
    
    # 求文件a.txt中总共包含的字符个数?思考为何在第一次之后的n次sum求和得到的结果为0?(需要使用sum函数)
    
    with open('a.txt','r',encoding='utf-8') as f:
        res=sum(len(line) for line in f)
        print(res)
    练习

    递归

      递归调用:在调用一个函数的过程中,直接或者间接调用该函数本身,称之为递归调用

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

    def func(n):
        print('--->',n)
        func(n+1)
    
    func(0)
    
    import sys
    print(sys.getrecursionlimit())  #查看递归深度
    sys.setrecursionlimit(2000)     #修改递归最大深度
    View Code
    def age(n):
        if n == 1:
            return 18
        return age(n-1) + 2
    
    res=age(5)
    print(res)
    l=[1,[2,[3,[4,[5,[6,[7,]]]]]]]
    
    def func(l):
        for item in l:
            if type(item) is list:
                func(item)
            else:
                print(item)
    
    func(l)
    View Code

    二分法 

    #实现类似l(num)的功能
    l=[1,2,30,45,57,68,78,93,100] #从小到大排列的数字列表
    
    def binary_search(l,num):
        print(l)
        if len(l) == 0:
            print('not exist')
            return
        mid_index=len(l)//2
        if num >l[mid_index]:
            binary_search(l[mid_index+1:],num)
        elif num < l[mid_index]:
            binary_search(l[0:mid_index],num)
        else:
            print('find it')
    
    binary_search(l,688)
    
    #实现类似l(num,index)的功能
    l=[1,2,10,20,30,55,67,87,92,102,293,304]
    
    def search(num,l,start=0,stop=len(l)-1):
        if start <= stop:
            mid=start+(stop-start)//2
            print('start:[%s] stop:[%s] mid:[%s] mid_vla:[%s]'%(start,stop,mid,l[mid]))
            if num > l[mid]:
                start=mid+1
            elif num <l[mid]:
                stop=mid-1
            else:
                print('find it',mid)
                return
            search(num,l,start,stop)
        else:
            print('not exist')
            return
    
    search(30,l)
    View Code

    匿名函数

      lambda x,y:x+y

    #应用
    s='hello'
    l=[1,2,3]
    g=zip(s,l)
    print(list(g))
    
    salaries={
        'lary':3000,
        'jone':100000000,
        'tom':10000,
        'jerry':2000
    }
    
    #zip/max/min/sorted/
    g=zip(salaries.values(),salaries.keys())
    print(max(g))
    
    print(max(salaries,key=lambda k:salaries[k]))
    print(min(salaries,key=lambda k:salaries[k]))
    print(sorted(salaries,key=lambda k:salaries[k]))
    print(sorted(salaries,key=lambda k:salaries[k],reverse=True))
    
    #map
    names=['lary','jone','tom','lily']
    print(list(map(lambda name:"%s_01"%name,names)))
    
    #filter
    names=['lary_01', 'jone_01', 'tom_01', 'lily']
    g=filter(lambda x:x.endswith('01'),names)
    print(list(g))
    
    from functools import reduce
    print(reduce(lambda x,y:x+y,range(1,101),100))
    应用

    内置函数

      查看内置函数:https://docs.python.org/3/library/functions.html?highlight=built

  • 相关阅读:
    vue里面的v-for列表循环
    浅谈Vue.use
    js 限制输入框只能输入数字的问题
    vue computed的执行问题
    前端 html 篇
    函数声明 及 名称问题
    文件读写操作
    异常以及异常处理框架探析
    使用JDBC插入数据到ORACLE,使用标识列自增列
    session超时跃出iframe并跳到登陆页面(转载)
  • 原文地址:https://www.cnblogs.com/iamluoli/p/8182476.html
Copyright © 2011-2022 走看看