zoukankan      html  css  js  c++  java
  • 7.12函数(四)

    一、函数递归

    1.什么是递归

    函数在调用阶段直接或者间接的又调用了自身

    (1)直接

    def func():
        print('from func')
        func()
    func()

    死循环,无限调用函数

    (2)间接

    def index():
        print('from index')
        login()
    
    def login():
        print('from login')
        index()
    index()

    也是死循环,无限调用这两个函数,不是在自身函数中直接调用,而是间接调用

    2.递归深度

    Python为了避免函数无限递归下去,设置了一个函数递归深度(重复执行上限),避免函数无限递归,导致计算机内存空间溢出(发生卡死,死机)。

    (1)如何查看递归深度

    import sys  # 调用模块
    print(sys.getrecursionlimit())  # 查看递归深度

    递归深度(重复调用)默认是1000,不过不是很准确

    def func(n):
        print('from func',n)
        func(n+1)
    func(1)  # 精确一点的python中最大递归深度是998左右

    精确一点的python中最大递归深度是998左右

    (2)如何修改最大递归深度

    import sys  # 调用模块
    sys.setrecursionlimit(2000)  # 修改递归深度
    def func(n):
        print('from func',n)
        func(n+1)
    func(1) 

    结论:函数不应该无限制的递归下去

    3.递归用在什么地方

      如果让函数无限制的递归下去没有任何意义,那递归应该用在什么场景?

    举个例子:

      询问A的年龄,A说比B小两岁,又问B,B说比C小两岁,再问C,C说比D小两岁......,直到E说他26岁,一个个推导得出A18岁

    递归分为两个阶段:

      (1)回溯:就是一次次重复询问的过程,这个重复的过程必须建立在每一次重复问题的复杂度都应该下降,直到有一个最终的结束条件(就是E说出26岁)

      (2)递推:一次次往回推导的过程(推导出A18岁)

    用代码演示这个例子:

    '''
    age(A) = 18
    age(B) = age(A) + 2
    age(C) = age(B) + 2
    age(D) = age(C) + 2
    age(E) = age(D) + 2
    age(1) = 18
    age(2) = age(1)+2
    age(n) = age(n-1)+2  # n>1
    '''
    
    def age(n):
        if n == 1:  # 必须要有结束条件
            return 18  # 返回18岁
        else:
            return age(n-1) + 2
    res = age(5)
    print(res)
    View Code

    如何做到:

      将列表中的数字依次打印出来:l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,]]]]]]]]]]]]]

    推导思路:

    l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,]]]]]]]]]]]]]
    for i in l:
        if type(i) is int:
            print(i)
        else:
            for item in i:
                if type(item) is int:
                    print(item)
                else:
                    for j in item:
                        if type(item) is int:
                            print(item)
                        else:
                            ...  # 无限重复,前提还得知道有多少层列表

    如果不知道多少层列表怎样做

    l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,]]]]]]]]]]]]]
    def get_num(l):
        for i in l:
            if type(i) is int:  # 如果是整型就打印
                print(i)
            else:  # 否则再循环这个列表
                get_num(i)
    get_num(l)

    结论:递归函数不需要考虑循环的次数,只需要把握结束的条件即可

    二、算法之二分法

    1.什么是算法

      解决问题的高效率的方法

    2.如何实现:

      找到num=345是不是在 l = [1,3,5,12,57,89,101,123,146,167,179,189,345]列表中

    l = [1,3,5,12,57,89,101,123,146,167,179,189,345]
    num = 345
    for i in l:
        if num == i:
            print('找到了')

    如果这个列表有非常多数据,那查找效率就会变低,算法就是提高效率的方法,比如这里可以用二分法

    3.二分法

      先在列表中间找,然后判断出在哪一边,然后在那一边的中间再找,没找到就再重复上述操作,提高查找效率

    l = [1,3,5,12,57,89,101,123,146,167,179,189,345]
    def get_num(l,target_num):
        print(l)  # 把每次切取到的列表打印下
        if not l:  # 判断列表是否为空了,空了还没找到就说明不在列表中
            print('你要找的值不在列表中')
            return
        middle_index = len(l) // 2  # 获取列表中间的索引
        if target_num > l[middle_index]:  # 判断target_num跟middle_index对应的数字的大小
            num_right = l[middle_index + 1:]  # 切取列表右半部分
            get_num(num_right,target_num)  # 再递归调用get_num函数,传入的列表变成切取的新列表
        elif target_num < l[middle_index]:  # 判断target_num跟middle_index对应的数字的大小
            num_left = l[0:middle_index]  # 切取列表左半部分
            get_num(num_left, target_num)  # 再递归调用get_num函数,传入的列表变成切取的新列表
        else:  # target_num = l[middle_index]的情况
            print('找到了')
    get_num(l,345)
    get_num(l,666)

    使用二分法有一个前提:

    容器类型里面的数字必须有大小顺序,没有顺序可以使用 sort() 进行排序

    三、三元表达式

    1.比较大小的函数

    def my_max(x,y):
        if x > y:
            return x
        else:
            return y
    print(my_max(1,5))

    当x大的时候返回x,当y大的时候返回y,也就是当某个条件成立做一件事,不成立做另外一件事

    2.如何用三元表达式表示这个函数

    x = 1
    y = 5
    res = x if x > y else y  # 如果if后面的条件成立返回if前面的值,否则返回else后面的值
    print(res)

    如果if后面的条件成立返回if前面的值,否则返回else后面的值

    3.三元表达式的固定语法结构

    值1 if 条件 else 值2

       条件成立返回值1

       条件不成立返回值2

    4.三元表达式的应用场景

      三元表达式只推荐只有两种情况的可能下

    例如:

    is_free = input('请输入是否免费(y/n)>>>:')
    is_free = '免费' if is_free == 'y' else '收费'
    print(is_free)
    username = input('username>>>:')
    res = 'NB' if username == 'francis' else '垃圾'
    print(res)

    四、列表生成式

    1.如何实现:

      使列表中的字符串后面加上字符 _NB:l = ['tank','nick','oscar','sean']

    l = ['francis','jason','tank','egon']
    l1 = []
    for name in l:
        l1.append('%s_NB'%name)
        # l1.append(name + '_NB')  # 等价于上面的办法,不推荐使用,python中这种字符串拼接效率太低
    print(l1)

    如何简单实现,需要用到列表生成式

    2.列表生成式

    l = ['francis','jason','tank','egon']
    res = ['%s_NB'%name for name in l]  # for循环依次拿出name交给for前面的,作为列表的一个个元素
    print(res)

    原理:for循环依次拿出name交给for前面的,作为列表的一个个元素

    3.列表生成式还可以加上if判断

      取出列表中以 _NB结尾的元素:l = ['francis_NB','jason_NB','tank_NB','egon']

    l = ['francis_NB','jason_NB','tank_NB','egon']
    res = [name for name in l if name.endswith('_NB')]  # 后面不支持再加else的情况
    # 先for循环依次取出列表里面的每一个元素
    # 然后交由if判断,条件成立才会交给for前面的,作为列表的一个个元素
    # 如果条件不成立,当前的元素,直接舍弃
    print(res)

    原理:先for循环依次取出列表里面的每一个元素,然后交由if判断,条件成立才会交给for前面的,作为列表的一个个元素,如果条件不成立,当前的元素,直接舍弃

    五、字典生成式

    1.如何实现:

      把两个列表的数值一一对应,组成一新个字典:l1 = ['name','password','hobby']、l2 = ['francis','123','read']

    l1 = ['name','password','hobby']
    l2 = ['francis','123','read']
    d = {}
    for k,v in enumerate(l1):  # v是新字典的key,k是l2值对应的索引
        d[v] = l2[k]
    print(d)

    2.字典生成式

    l = ['francis','123','read']
    d = {i:j for i,j in enumerate(l) if j != '123'}  # 还可以加上if判断,如果j不等于'123'就交个for前面的,否则舍弃
    print(d)

    3.集合生成式

    s = {i for i in range(10) if i != 4}
    print(s)

    只要记住这个格式,外面加什么就生成什么(基本)

    4.生成器表达式

    t = (i for i in range(10) if i != 4)  # 这样写不是元组生成式,而是生成器表达式
    print(t)  # 返回的是个老母猪
    for i in t:
        print(i)

    六、匿名函数

    1.什么是匿名函数

      没有名字的函数(也就意味着之后无法通过函数名加括号调用),所以是临时存在的函数,用的时候才存在,用过就没了

    2.怎么用

    lambda x,y:x+y  # 求和的匿名函数
    
    就等价于下面的有名函数
    
    def my_sum(x,y):
        return x + y  # 求和的有名函数

    lambda x,y:x+y

    (1)冒号(:)左边的相当于函数的形参

    (2)冒号(:)右边的相当于函数的返回值

    (3)匿名函数通常不会单独使用,而是配合内置函数一起使用

    (4)也可以加括号使用,不过用完就没了

    res = (lambda x,y:x+y)(1,2)  # 加括号使用并传参数
    print(res)

    (5)也可以给匿名函数命名,命名知乎就变成有名函数了,但失去了匿名函数的意义

    func = lambda x,y:x+y
    print(func(1,2))  # 函数加括号调用

    七、常用的内置函数

    1.max、min(最大值,最小值)

      得出薪资最高的人的名字(比较薪资,返回人名):

      d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000}

    (1)直接用max比较

    d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000}
    print(max(d))  # 比较的是字典的key的大小,得出tank,不对

    比较的是字典的key的大小(字典暴露给用户的只有key)

    (2)调用函数的办法

    d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000}
    def index(name):
        return d[name]
    print(max(d,key=index))  # max支持传一个函数,这样传入的key就被函数index变成了value,比较的就是value了

    这样index函数只是为下面的比较大小服务的,就可以简化成匿名函数

    d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000}
    print(max(d,key=lambda name:d[name]))  # 冒号左边是函数的形参,右边是返回值

    得出薪资最低的人也是这样

    d = {'francis':30000, 'jason':20000, 'egon':15000, 'tank':10000}
    print(min(d,key=lambda name:d[name]))

    2.map(映射)

      把列表中的每个数字都加1:l = [1,2,3,4,5,6]

    l = [1,2,3,4,5,6]
    res = map(lambda a:a+1,l)  # map是基于for循环的,返回的是一个老母猪
    print(list(res))  # list会循环老母猪里的数值组成列表

    3.zip(拉链)

      让列表中的值一一组合在一起:l1 = [1,2,3]、l2 = ['jason','egon','tank']、l3 = ['a','b','c']

    l1 = [1,2,3,4]
    l2 = ['jason','egon','tank']
    l3 = ['a','b','c']
    print(list(zip(l1,l2,l3)))  # 得出的是列表中包含一对对元组
    # 如果某列表元素多于其他列表也不影响,只保留能对应上的部分

    4.filter(过滤)

      返回一个新列表,去除3:l = [1,2,3,4,5,6]

    l = [1,2,3,4,5,6]
    res = filter(lambda x:x != 3,l) # filter是基于for循环的,返回的是一个老母猪
    print(list(res))  # list会循环老母猪里的数值组成列表

    5.sorted(排序)

      给列表排序:l = [3,5,1,4,2,4]

    l = [3,5,1,6,2,4]
    res = sorted(l)  # 相当于sort,默认升序
    print(res)
    res1 = sorted(l,reverse=True)  # 也可以传参数,变为降序
    print(res1)

    6.reduce

    类似于一个工厂,你给我多份材料,我只返回一个结果(给我一个列表,只返回一个值)

      把列表中的值相加:l = [1,2,3,4,5,6]

    (1)没有初始值的时候

    l = [1,2,3,4,5,6]
    from functools import reduce  # reduce不可以直接用,需要先导入一个模块
    print(reduce(lambda x,y:x+y,l))  # 没有初始值
    # 没有初始值的时候,第一次获取两个值然后相加,之后每次获取一个值与上一次相加的结果再相加

    (2)有初始值的时候

    l = [1,2,3,4,5,6]
    from functools import reduce  # reduce不可以直接用,需要先导入一个模块
    print(reduce(lambda x,y:x+y,l,10))  # 初始值为10,初始值就是第一个参数
    # 有初始值的时候,第一次获取一个值然后相加,之后每次获取一个值与上一次相加的结果再相加
  • 相关阅读:
    Centos7安装dockercompose
    windows环境下python2和python3版本的切换
    移动硬盘无法读取分区表修复RAW格式修复
    网络与信息安全初探
    MyBatis下在插入数据时获得MySQL自增长序列的值
    CentOS7下mongodb忘记密码后重置密码
    url中有空格等特殊字符及中文字符处理
    通过linux mail实现网站存活监控告警通知
    如何通过SecureCRT转发功能实现外网访问内网服务
    java转JSON串的几种方式
  • 原文地址:https://www.cnblogs.com/francis1/p/11181995.html
Copyright © 2011-2022 走看看