• day13-三元表达式,生成式,递归函数,匿名函数


    其实学到这,函数部分的精髓你都已经学的差不多了,那今天的内容就再讲函数的其他方法使用介绍

    今天讲的内容有,三元表达式,列表生成式,字典生成式集合生成式以及生成器表达式(生成器生成式),还有递归函数和匿名函数.

    别看介绍这么多.其实除了递归函数有一点难运用,其他的都是和记用法一样.

    话不多说.进入今日主题

    一.三元表达式

    概念:其实三元表达式就是一个对流程控制if,else的优化.

    语法:一元 if 二元 else 三元

    其中一元指的是当if后面的条件,成立的情况下,返回的值.

    二元值的就是判断的条件

    三元值的就是当if后面的条件,不成立的情况下,返回的值

    返回的是一元或者三元的值

    例子:比较俩个数字的大小,并返回大的数字

    方法1:用函数

    def max2(x,y):
        if x > y:
            return x
        else:
            return y
    print(max2(111,432))  # 432
    

    方式2:用三元表达式

    x = 111
    y = 432
    res = x if x > y else y
    print(res)  # 432
    

    即三元表达式就一个结论:# 即if中间的为判断条件,左边的为条件成立返回的值,右边为条件不成立返回的值

    res1 = 'yes' if x > y else 'no'

    接下来就是一些生成式

    生成式

    列表生成式

    概念:在列表内做一些表达式操作,将返回的值添加到一个新列表

    语法:[i for i in range(10) if i < 6]

    • 中间为for循环执行的代码体
    • if 后面表示的是循环体内的一个if分支,一个条件判断,可选参数
    • 最前面的i表示的是要返回的值

    案例:将0-9添加到一个列表中

    方式1:平常的代码

    l = []
    for i in range(10):
        l.append(i)
    print(l)
    

    方式2:列表生成式

    l1 = [i for i in range(10)]
    print(l1)
    

    案例2:将0-9中大于6的添加到一个列表中

    方式1:平常的代码

    l2 = []
    for i in range(10):
        if i < 6:
            l2.append(l2)
    

    方式2:列表生成式,如何优雅的取代了forif

    l3 = [i for i in range(10) if i < 6]
    print(l3)
    

    案例3:将列表中的元素都加上'_sb'

    方式1:平常的代码

    names = ['song', 'liu', 'xiong']
    names1 = []
    for name in names:
        name = name + '_sb'
        names1.append(name)
    print(names1)
    

    方式2:列表生成式

    l4 = [name+"_sb" for name in names]
    
    print(l4)
    

    案例4:将列表中带_sb的名字打印,用列表生成式实现

    names2 = ['jkey', 'liu_sb', 'song_sb']
    names4 = [name for name in names2 if name.endswith("_sb")]
    print(names4)
    

    其实,你可以发现,列表生成式其实就是一个精简代码的一个内置方法.一般都是搭配for 循环使用

    那列表有生成器,其他的字典,元组,和集合呢??

    对他们都有对应的生成式.值得一提的是python没有元组表达式因为元组就是一个不可变的列表.

    如果你想要进行表达式 ,可以使用 list 和 tuple 之间的转换

    所以()在外面python就有了另外一层表达式的意思,即我们的生成器表达式

    那一步步来.让我们看看字典生成器怎么用

    字典生成式案例:

    dict1 = {f'k_{str(i)}': i**2 for i in range(10) if i > 3}
    print(dict1)  # {'k_4': 16, 'k_5': 25, 'k_6': 36, 'k_7': 49, 'k_8': 64, 'k_9': 81}
    

    还有集合生成器的使用

    集合生成器案例:

    set1 = {i for i in range(10) if i > 3}
    print(set1)  # {4, 5, 6, 7, 8, 9}
    

    和列表生成器的玩法差不多,所以大家看一下案例,知道怎么使用就可以了

    还是就是我们的生成器表达式

    生成器表达式(==>生成器生成式)

    也放俩个案例,来帮助大家理解吧

    案例1:生成器表达式的简单使用

    res = (i for i in range(3))  # 这里的()表示的就是一个生成器表达式
    print(res)  # 返回的类型是 生成器对象,即自定义的迭代器对象<generator object <genexpr> at 0x0000029056119CC8>
    
    # 那下面就可以使用next方法去遍历取值了
    print(next(res))  # 0
    print(next(res))  # 1
    print(next(res))  # 2
    print(next(res))  # StopIteration
    
    
    

    案例2:统计一个文件的字符长度

    with open('a.txt', mode='rt', encoding='utf-8') as f:
        # 方法1:之间将其全部读到内存.再计算其文件的长度
        res = f.read()
        print(len(res))
        # 方法2:用for循环一行一行的计算长度,并累加
        res = 0
        for line in f:
            res += len(line)
        # 方法3:用列表生成器进行上面的方式2操作
        res1 = sum([len(line) for line in f])
        # 进一步,用生成器
        res2 = sum((len(line) for line in f))
        # 俩层括号可以简化成一个,即
        res3 = sum(len(line) for line in f)
    

    那我们用生成器的一个好处是撒?是的那就是昨天讲的,节省内存空间,即这里因为是一个迭代器对象,所以它不会像列表(可迭代对象)一样,放的是一个个的值在内存中,而是一个可以产生值的对象,来一个就产生一个,要下一个值,上一个就以及在内存中释放了.

    是不是发现这些生成式很简单,只要记下怎么使用就好了.

    那接下来就来一个带点难度的

    递归函数

    概念:在调用一个函数的内部又调用自己,所以递归调用的本质就是一个循环的过程

    什么意思??循环??那我用while循环和for循环不可嘛

    别着急

    我们先来看看,递归函数长撒样

    def func():
        print("func")
        func()
    
    func()
    

    上面就是一个简单的递归函数,即在函数体内部执行函数本身.

    我们去执行看看

    返回结果:

    func
    func
    ....
    RecursionError: maximum recursion depth exceeded while calling a Python object
    

    欸,它会报错是不是

    那是因为我们只是让它执行了函数体本身,但是并没有结束条件啊,所以就相当于是一个死循环了.

    而为何这里会报错呢?

    是因为python以及为我们考虑到了,你可能会有一个死循环的函数.所以它给我们内部定义了一个可以循环的最大上限次数,一般为1000次.1000次过后则抛异常.为的就是优化内存

    可以通过sys模块下的getrecursionlimit,查看最大循环次数

    也可以通过setrecursionlimit来重新设置最大循环次数

    即下方代码

    import sys
    sys.setrecursionlimit(2000)  # 设置成最大次数为2000
    print(sys.getrecursionlimit())  # 查看最大循环的次数(默认为1000)
    

    所以我们递归函数有一个大前提:递归调用一定要在某一层结束

    递归其实是有俩个阶段的

    即回溯和递推

    1、回溯:向下一层一层挖井
    2、递推:向上一层一层返回

    下面来俩个案例.方便大家理解

    现在我有一个需求:

    我去问一个人的年龄,第一个人说我的年龄是比第二个人大10岁,然后我们又去问第二个人,第二个人说:我的年龄比第三个人的年龄大10岁,然后我们又去问第三个人,第三个人说.我的年龄比第四个人的大10岁....,n次后,第n个人说我的年龄是18岁,算出第一个人的年龄

    现在我们反向思维想一下,代码如下

    age(n) = age(n-1) + 10
    ....
    age(5) = age(4) + 10
    age(4) = age(3) + 10
    age(3) = age(2) + 10
    age(2) = age(1) + 10
    age(1) = 18
    

    欸,我们看到这不就是一个循环的过程嘛?

    我们是不是可以用递归函数试试?

    说了就干

    def age(n):  # n 表示有n个人
        if n == 1:  # 即是我们告诉了实际年龄的那个人
            return 18
        return age(n-1) + 10  # 这里表示执行的循环关系
    

    我们调用试试

    res = age(5)
    print(res)  # 58
    

    输出58 是不是没问题

    如果这个你没理解,没关系,我们还有案例

    当然这个案例,就更好的说明了递归函数使用的恰到好处

    案例需求: 一个列表 nums = [1,[2,[3,[4,[5,[6,[7,]]]]]]],我们取出列表的每一个值.

    我靠.这不是玩我们嘛?谁没事套这么多列表,是的,我就是玩你.来试着实现吧.

    我想我们大家一开始都会想到我们熟悉的for循环,对 for 循环是可以取出来.

    for循环代码

    for num in l:
        if type(num) is list:
            for num1 in num:
                if type(num) is list:
                    for num2 in num1:
                        ...
        else:
            print(num)
    

    我靠,这什么玩意?有几个列表我for几次???

    明显这不行.

    我们看看根本,我们是一个个拿到新的列表,每次都对新列表做一样的操作,但里面执行的明明是一样的,那个新列表来自的就是上一个的列表中的第二个值.

    所以这时候我们想到了我们的递归函数.

    代码示例:

    nums = [1,[2,[3,[4,[5,[6,[7,]]]]]]]
    
    def get(l):
        for num in l:
            if type(num) is list:
                get(num)  # 让他每一次来的都是一个新列表,这不久满足了我们的要求嘛
            else:
                print(num)
    
    get(nums)  # 1,2,3,4,5,6,7
    

    递归函数还有一个用处

    我们看看下面一个列表

    nums = [-3,1,3,7,13,23,37,43,57,63,77,91,103]

    我要看看一个数在不在这个列表里面

    很简单嘛

    find_num = 65
    for num in nums:
    	if nm == find_num:
    		print('you got it')
    		break
    else:
    	print('no exitc')
    

    但你想想如果你查找的值在列表的前面还好,就遍历了,几次,如果是最后面呢?我们是不是要遍历很多次?而且前面的都是无效的遍历.

    这时候,用我们的递归函数就有一个好处了.

    我们可以拿到中间的那个值,然后再判断,要查找的这个数,和中间这个数比较,大了的话,我就再在中间这个数的右边查找,小了的话,就走这个数的左边查找.依次类推,是不是就很大程度上加快了查询,这就是我们传说中的二分法

    来我们用代码实现:

    二分法

    nums = [-3,1,3,7,13,23,37,43,57,63,77,91,103]
    find_num = 64
    
    def find(nums,find_num):
        print(nums)
        if len(nums) == 0:  # 当这个列表被分为空了还没找到,那说明这个要查找的数不在这个列表中
            print("not exists")
            return  # 就不会往下执行了,解决了如果列表为空,还根据索引1取值的异常
        mid_index = len(nums) // 2  # 拿到列表的中间索引
        if find_num > nums[mid_index]:
            # in the right
            find(nums[mid_index+1:],find_num)
        elif find_num < nums[mid_index]:
            # in the left
            find(nums[:mid_index], find_num)
        else:
            print('you got it')
    
    
    find(nums,find_num)
    

    这个递归函数是不是很有意思.

    接下来,还有更有意思的.

    我们之前用的函数是不是都带一个名称的.例如 def func():pass 其中的func就是这个函数的名字.那我们是不是也可以有没有名称的函数呢?是的,它就是我们的匿名函数

    匿名函数 lambda

    概念:一个没有名字的函数,功能却和函数一样

    语法: lambda x,y:x + 2 * y

    • lambda 后面的 x,y 表示的是匿名函数的参数, :后面的表示的是函数的返回值

    特点:用于临时用一次的

    使用场景:一般搭配内置的函数使用.

    下面是匿名函数的俩种之间使用的案例:

    方法1:看完就忘(因为这样用我还不如用有名函数)

    d = lambda x,y:x + 2*y
    print(d)  # <function <lambda> at 0x000001CA0CBB7F78>
    res = d(1,2)
    print(res)  # 5
    

    方法2:可以这样用,但可读性差

    res = (lambda x,y:x + 2 * y)(1,2)
    print(res)  # 5
    

    所以还是之间来和我们的新朋友,几个内置函数一起来玩吧

    那就边写案例,边介绍吧

    案例1:下方有一个员工工资字典,我们根据工资的多少,分别将工资最高的和最低的员工姓名,以及给他们

    按照多到少,少到多的员工信息

    salaries = {
        "egon": 3000,
        "tom": 10000,
        'zxx': 1000
    }
    

    取出最高的,这里先介绍一下,max()这个内置函数的作用

    max函数

    功能:返回一个可迭代的对象的最大值

    语法: max(iteration, [key=func])

    • 其中iteration表示的是可迭代对象
    • key=func,可选参数,表示按照什么依旧来返回最大值
      • func为一个函数内存地址

    来加到我们的案例中

    def func(k):
        return salaries[k]  # 依据是字典的value即薪资
    
    
    print(max(salaries, key=func))  # 返回的是tom
    

    我们再将函数变为匿名函数试试

    print(max(salaries, key=lambda k: salaries[k]))  # 是等同于 print(max(salaries, key=func))
    

    ok,完成了需求1,返回最大薪资的员工姓名

    需求2:返回薪资最低的员工姓名

    先介绍min函数

    和max函数的使用方法一样,但是它的功能是返回一个可迭代的对象的最小值

    语法: max(iteration, [key=func])

    • 其中iteration表示的是可迭代对象
    • key=func,可选参数,表示按照什么依旧来返回最大值
      • func为一个函数内存地址

    加到我们案例中

    print(min(salaries, key=lambda k: salaries[k]))
    

    需求2也满足了

    需求3和需求4,返回他们的顺序,即从低到高和从高到低

    函数sorted

    功能:返回一个排序后的可迭代对象

    语法:max(iteration, [key=func],[reverse=False])

    • 其中iteration表示的是可迭代对象
    • key=func,可选参数,表示按照什么依旧来返回最大值
      • func为一个函数内存地址
    • reverse=False,表示默认的以升序排序

    放到案例中

    print(sorted(salaries, key=lambda k: salaries[k]))  # ['zxx', 'egon', 'tom']
    print(sorted(salaries, key=lambda k: salaries[k], reverse=True))  # ['tom', 'egon', 'zxx']
    

    ok,需求都完善了

    其他内置函数

    下面还有一些其他内置函数的玩法.大家可以试着敲敲看看

    # map
    res = list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))  # map()返回的是 <map object at 0x00000227FF6FEBC8>
    print(res)
    
    names = ["lxx", 'hxx', "wxx", 'lili']
    #                    规则
    #       "lxx_sb","hxx_sb"
    
    l = (name + "_sb" for name in names)
    res = map(lambda name:name + "_sb",names)
    print(list(res))
    
    # filter  #  过滤出某个元素
    names = ["lxx_sb",'egon',"wxx_sb",'lili_sb']
    print([name for name in names if name.endswith('sb')])
    
    res = filter(lambda name:name.endswith('sb'),names)
    print(list(res))
    
    # reduce # 拼接元素
    from functools import reduce
    
    res = reduce(lambda x,y:x+y,[1,2,3])
    res = reduce(lambda x,y:x+y,["aa","bb","cc"])
    print(res)
    
    
    res = pow(10,2,3)  # 等同于 10 ** 2 % 3  
    print(res)
    

    最后给大家来介绍一下什么是面向过程编程

    面向过程编程:

    ​ 核心是"过程"二字,过程就是解决问题的步骤.即先干啥,再干啥,后干啥
    ​ 所以基于该思想编写程序就好比设计一条一条的流水线

    优点:复杂的问题流程化,将一个大问题变成了一个个的小问题,进而就实现了简单化
    缺点:牵一发而动全身,扩展性差

    总结:

    1.三元表达式 xxx if xxx else xxx 第一个xxx 为第二个xxx成立时返回的结果,第三个xxx表示的是第二个xxx不成立时返回的结果

    2.生成式:[i for i in range(10) if i > 5] 这样一个模板实例

    3.递归函数:在函数内调用函数本身,一定要有结束条件,才有意义.

    4.匿名函数:lambda , lambda x,y:x+y,:前的为参数,后面的为返回值

    5.一些内置方法

    max()返回最大值
    min()返回最小值
    sorted()默认升序返回,当参数reverse=True时,为降序返回
    以上内置都有key=func的参数可选 表示的比较的依据,func为一个函数内存地址
    map() 映射,改变可迭代对象的值
    filter()  过滤
    reduce() 拼接元素
    
  • 相关阅读:
    Lua基础之Function
    Lua基础之table详解
    Lua基础之语法
    详解C#中的反射(转载)
    Cocos-x 3.2:从C++过渡到Lua(转载)
    cocos2dx-Lua中出现的问题
    (转载)Cocos2dx-OpenGL ES2.0教程:纹理贴图(6)
    (转载)Cocos2dx-OpenGL ES2.0教程:你的第一个立方体(5)
    hdu 2098 分拆素数和(一个偶数拆分成两个不同素数和 拆法数量)
    51Nod
  • 原文地址:https://www.cnblogs.com/jkeykey/p/14217874.html
Copyright © 2020-2023  润新知