• python学习week5-递归,匿名函数、生成器


    1、递归函数

    1.1、递归函数的限制

      (1)递归一定要有退出条件,并且递归调用一定要执行到这个退出条件;如果没有退出条件,就是无限调用,会耗尽所有资源(栈空间);

      (2)递归调用的深度不易过深,Python对递归调用的深度做了限制,以保护解释器;

    1.2、递归实例

    ①、递归实现斐波拉契数列

    # version1:数学公式版本
    def fib(n):
        return 1 if n<3 else fib(n-1)+fib(n-2)
    
    print(fib(10))
    
    分析:此版本虽然看着简洁明了,但是会有很大的效率问题,当n操作35以后计算结果就非常慢
    
    # version2:利用上一次结果
    def fib(n,a=0,b=1): # n=3
        if n<3:
            return a+b
        else:
            a,b=b,a+b  # 0,1=1,1
            return fib(n-1,a,b)
    
    分析:版本每次都利用了上一次运算的结果,所以效率相对于第一个版本来说,快了不少;
    
    # for循环实现
    a,b=0,1
    for i in range(10):
        a,b=b,a+b
        print(a)
    
    分析:版本二就是根据for循环演变而来

    ②、递归实现阶乘

    def fac(n,sum=1):
        if n==1:
            return 1
        return n*fac(n-1)
    
    def fac(n,sum=1):
        sum=sum*n
        if n<2:
            return sum
        return fac(n-1,sum)
    
    # 版本二将每次计算的结果带入了下一次计算

    ③、将一个数逆序放入列表

    nums='1234'
    print(nums[len(nums)-1])
    l=[]
    # for循环实现
    for i in range(len(nums)-1,-1,-1):
      l.append(nums[i])

    print
    (l)

    # 列表拼接实现
    def revert(x): if x == -1: return [] return [nums[x]] + revert(x-1) print(revert(len(nums)-1))
    # 字符串切片实现
    def revert(x,target=[]): if x: target.append(x[-1]) revert(x[:-1]) return target print(revert(nums))

    ④、递归解决猴子吃桃问题

    '''
    x
    d1=x//2-1
    d2=d1//2-1
    d3=d2//2-1
    ...
    ...
    d9=d8//2-1 ==> 2(d9+1)=d8=d7/2-1
    '''
    peach=1
    for i in range(9):
        peach=2*(peach+1)
    print(peach)
    
    '''
    这题得倒着推。第10天还没吃,就剩1个,说明第9天吃完一半再吃1个还剩1个,假设第9天还没吃之前有桃子p个,可得:p * 1/2 - 1 = 1,可得 p = 4。以此类推,即可手算出。
    代码思路为:第10天还没吃之前的桃子数量初始化 p = 1,之后从9至1循环9次,根据上述公式反推为 p = (p+1) * 2 可得第1天还没吃之前的桃子数量。
    for循环中的print()语句是为了验证推算过程而增加的。代码如下:
    p = 1 print('第10天吃之前就剩1个桃子') for i in range(9, 0, -1): p = (p+1) * 2 print('第%s天吃之前还有%s个桃子' % (i, p)) print('第1天共摘了%s个桃子' % p) ''' # 递归实现 def peach(n=10): if n == 1: return 1 return (peach(n-1)+1)*2 print(peach())

    2、匿名函数

    #  匿名函数:即没有名字的函数;

      没有名字如何定义?

      没有名字如何调用?

    # Pyhton借用lambda表达式解决以上问题;

    # 格式: lambda 参数列表:表达式 # 此表达式相当于函数体内的return 后面的语句;

    # 特点:

      ①:使用lambda关键字来定义匿名函数;

      ②:参数列表不需要小括号;

      ③:冒号是用来分割参数列表和表达式的;

      ④:不需要使用return,表达式的值,就是匿名函数的返回值;

      ⑤:lambda表达式只能写在一行上,也被称为单行函数;(函数体内逻辑复杂的不适用);

      ⑥:一般用于高阶函数传参时,可以简化代码;

    #  自定义函数可以改写为lambda形式;

    def fun(x,y):
        return x+y
    
    f=lambda x,y:x+y # 不建议这么用;
    # (1)相当于给lambda函数赋值函数名f,
    # (2)函数f的功能与fun函数的功能一样,即fun函数可以改写为下面lambda形式;
    
    print(fun)
    print(f)
    '''
    <function fun at 0x000001CD55452E18> 
    <function <lambda> at 0x000001CD558A9D08>
    '''
    l=[x for x in (lambda *args:map(lambda x:x+1,args))(*range(5))]
    '''
    分析: 
    (*range(5)) 先解构为(0,1,2,3,4) 传递给 *args, 然后执行map里面的函数;
    map(func,iter)  ==> func=lambda x:x+1 iter=args, 然后x向iter也就是args中取值
    [0,1,2,3,4] 经过func处理后返回为[1,2,3,4,5]
    '''
    print(l) # [1, 2, 3, 4, 5]
    
    l=[x for x in (lambda *args:map(lambda x:(x+1,args),args))(*range(5))]
    '''
    分析:这个实例和上一个差不多,只是在内层lambda返回类型变了,返回的为一个二元组(x+1,args),这个的args=iter=(0,1,2,3,4)
    '''
    print(l)
    [(1, (0, 1, 2, 3, 4)), (2, (0, 1, 2, 3, 4)), (3, (0, 1, 2, 3, 4)), (4, (0, 1, 2, 3, 4)), (5, (0, 1, 2, 3, 4))]
    s = "this is
    a	test"
    l=lambda x:' '.join(x.split())
    print(l(s)) # 运行结果:this is a test
    
    c = lambda **Arg: Arg
    print(c()) # 返回一个空字典;

    3、生成器与迭代器

    3.1、迭代器

      # 迭代:是一个重复的过程,每一次重复都是基于上一次的结果而来;

      # 可迭代对象:凡是可调用__iter__方法的,都是可迭代对象(iterable);

    3.2、迭代器与可迭代对象的区别

      ①:凡是可用于for循环的对象,都是可迭代对象;

      ②:凡是可以作用于next()函数的对象,都是迭代器对象;

      ③:list、dict、str、等都是可迭代对象,并不是迭代器对象,因为next()函数无法调用他们,可以使用iter()函数将他们转换为迭代器对象;

    3.3、for循环的原理

    # 基于for循环可以完全不依赖索引取值;

    d={'a':1,'b':2,'c':3}
    for k in d:
        print(d[k])
    '''
    1、执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    2、执行next(iter_dic),将得到的值赋值给k; ==> d.__iter__().__next__() ==> k='a'然后执行循环体代码;
    3、重复过程2,知道捕获异常StopIteration,循环结束;
    '''

    3.4、生成器generator:

      ①:生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到一个生成器函数,调用这个函数可以得到一个生成器对象;

    3.5、生成器函数:

      ①:函数体中包含yield语句的函数,返回生成器对象;

      ②:生成器对象是一个可迭代对象,也是一个迭代器;

      ③:生成器对象是延迟计算,惰性求值; # 节省内存空间;

      ④:在 Python中,使用yield返回的函数会变成一个生成器(generator)。在调用生成器的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行next()方法时从当前位置继续运行。

    '''
    斐波拉切数列生成器实现
    '''
    def fib(n,a=0,b=1):
        for i in range(n):
            a,b=b,a+b
            yield a
    g=fib(10)
    
    for i in g:
        print(i)
    
    #################
    def fib(n,a=0,b=1):
        count=0
        while count<n:
            a,b=b,a+b
            count+=1
            yield a
    
    for i in fib(10):
        print(i)

     # yield 和return的功能类似,都可以返回值;但是不同的是return只能返回一次值,而yield可以返回多次值;(能够直接返回到函数内部,非常牛逼的功能)

    def foo(count:int):
        print('start...')
        while True:
            yield count
            count+=1
    
    g=foo(10)
    print('===>第一次next')
    print(next(g))
    print('===>第二次next')
    print(next(g))
    print('===>第三次next')
    print(next(g))
    
    '''
    ===>第一次next
    start...
    10
    ===>第二次next
    11
    ===>第三次next
    12
    '''

    4、插入排序

    # 插入排序分析

    [0,1,9,8,5,6] 原始数列
    哨兵每次从无序区拿第一个作为哨兵
    
    [9,1,9,8,5,6] 
    第一趟:设定哨兵位等于s=9 ,有序区:1  无序区:9,8,5,6
    拿有序区1和无序区9 比较大小 , 1 不大于9  所以位置不改变, 比较后 有序区为:1,9  无序为:8,5,6;
    
    [8,1,9,8,5,6] 
    第二趟:s=8, 有序区为:1,9  无序为:8,5,6; 
    拿有序区9和无序8比较,9 > 8  => [8,1,9,9,5,6] =>j-1 => [8,1,8,9,5,6]
    
    [5,1,8,9,5,6]
    第三趟:s=5 ,有序1,8,9  无序:5,6
    9>5 ==> [5,1,8,9,9,6] ==> 8>5 ==> [5,1,8,8,9,6] ==> 1不大于5 ==>[5,1,5,8,9,6]
    
    总结:每次比较将无序区域第一个数拿来作为比较的哨兵,然后将有序区数和哨兵依次比较,比哨兵大的数往后放,
    直到比较到比哨兵小,然后将哨兵插入队列
    ######代码实现############
    def insert_Sort(l,nums=[0]): # nums=[0,1,9,8,5,6]
        '''
        实现插入排序
        :param l:
        :return:
        '''
        nums=nums+l
        for i in range(2,len(nums)): # i=3
            nums[0]=nums[i] #  num[0]=8
            j=i-1        
            if nums[j] > nums[0]:
                while nums[j] > nums[0]:
                    nums[j+1]=nums[j] 
                    j-=1  
                nums[j+1]=nums[0]  # 插入哨兵
        return nums[1:]
    
    l=[1,9,8,5,6]
    res=insert_Sort(l)
  • 相关阅读:
    php无限极分类
    如何使用百度地图
    如何在windows下用IDA优雅调试ELF
    [补] winpcap编程——EAPSOCKET实现校园网锐捷登录(mentohust)
    [补] winpcap编程——EAP协议与EAPSOCKET实现
    [补] windows C socket编程——大物实验预约
    [C++ Calculator 项目] 文件读入与可视化实现
    Area of Circle
    [C++ Calculator 项目] 基础运算实现
    [C++ Calculator 项目] 初试
  • 原文地址:https://www.cnblogs.com/soulgou123/p/9574292.html
Copyright © 2020-2023  润新知