我的Python成长之路---Day14匿名函数和函数的递归

版权声明:此博客实属作者原创,转载请注明出处! https://blog.csdn.net/Onion_cy/article/details/82997191

一、匿名函数

1. 什么是匿名函数
    def定义的是有名函数:            有名函数特点是可以通过名字重复调用
        def func():                          #func=函数的内存地址
            pass
    匿名函数就是没有名字的函数:特点是只能再定义时使用一次

2. 为何要用匿名函数
    强调:
        匿名函数的定义就相当于只产生一个变量值,而没有绑定任何名字,
        所以会在定义完之后就被回收,无法重复使用,只能在定义时使用一次
    应用:当某一个功能仅使用一次就没有再重复使用的必要了,就应该定义成匿名函数

3. 如何用匿名函数
    lambda x,y:x+y    (这是匿名函数固定的使用方法,lambda后面加上相应参数和函数体代码)

匿名函数的定义和函数定义差不多,在定义的时候,不需要使用def+函数名,直接使用lambda,后边同样需要传入参数,加冒号,在冒号后边就是函数体代码了,匿名函数的函数体代码一般都要一行完成,因此不能有if while等语句.但是可以用三元表达式.并且不需要加return,匿名函数自带return的效果,可以将冒号后边的函数体代码运行结果返回出来,和函数一样返回的仍然是函数的内存地址,看到函数内存地址就要有在后边加()去调用的冲动,所以在匿名函数后面直接加()并传入相应的参数就可以直接进行使用了

print(lambda x,y:x+y)             输出(lambda函数的内存地址):<function <lambda> at 0x000001DEF2AA1EA0>  
res=(lambda x,y:x+y)(1,2)      输出:3    可以直接在后边加()进行调用
print(res)

def sum2(x,y):                       如果使用有名函数去实现这个功能
    return x + y

max()函数

求出字典salaries中工资最高的人的名字

salaries = {
    'egon': 3000,
    'alex': 100000000,
    'wupeiqi': 10000,
    'yuanhao': 2000
}

print(max(salaries.values()))    这样写,比较的是字典中所有的value的最大值,输出结果为:100000000

def func():
    return salaries[k]
print(max(salaries.values(),key=func())


nums=[10,-1,11,9,23]            举这个例子是想说明max进行比较的时候他会自动判别要识别的内容,然后
print(max(nums))                按照它自己默认的方式进行比较和返回值出来,比如在这里比较一个列表.
                                他会自动将列表中的元素取出来进行对比,然后返回出来一个最大值,这个
                                最大值还是列表中的一个元素

max在使用的时候回自动使用要比较的数据类型,然后按照它本身的比较方法进行比较,然后给返回值,比如比较列表的时候,会返回列表中的元素;比较字典时会自动比较字典中的key,然后再返回其中一个key;比较字符串时,会按照从字符串的首字母开始比较,直到分出最大的,然后会返回一个字符串;

max()函数中有个参数key,这个key是函数的内存地址,在需要的时候可以定义一个函数传给key从而改变max默认的比较值

key=函数的内存地址: 作用是控制max函数的比较的值
def func(k):
    return salaries[k]

print(max(salaries,key=func))     输出结果:alex

这里使用改变max()函数中key的值,也就是改变比较依据来实现我们想要的结果

1. 将可迭代对象例如:salaries变成迭代器对象iter_obj
2. next(iter_obj)得到一个人名,然后将该人名当作参数传给key指定的函数,(在这里修改了max()的key参数)
   然后调用函数将函数的返回值当作比较依据
3. 比较大小,取出最大值对应的人名

max()的原理:
1. 将可迭代对象例如:salaries变成迭代器对象iter_obj
2. next(iter_obj)得到一个值(从迭代器对象中获取),然后再从迭代器对象中获取值将两个值进行比较,(这时候如果max()中的key值没有变化,max将默认从迭代器中取出来的第一个值作为默认比较对象,返回时也将会返回此类型的比较对象)
3. 比较大小,取出最大值

在这里使用有名函数当然可以,但是考虑到这个函数的功能仅在这里使用一次,所以将其写成匿名函数将更合理 更简便
print(max(salaries,key=lambda k:salaries[k]))

min()函数

min函数和max函数原理和使用方法都一样,只是功能不同而已
print(min(salaries,key=lambda k:salaries[k]))

sorted()函数

sorted排序
nums=[10,-1,11,9,23]
print(sorted(nums))
print(nums)

salaries={
    'egon':3000,
    'alex':100000000,
    'wupeiqi':10000,
    'yuanhao':2000
}

sorted(iterbale,key,reverse)三个参数,第一个参数是可迭代对象,第二个key是排序的依据(和max函数的key类似),第三个是反转排序(默认排序是从小到大)

print(sorted(salaries)                                         输出:['alex', 'egon', 'wupeiqi', 'yuanhao']
print(sorted(salaries,key=lambda k:salaries[k])) 输出:['yuanhao', 'egon', 'wupeiqi', 'alex']
print(sorted(salaries,key=lambda k:salaries[k],reverse=True))  输出:['alex', 'wupeiqi', 'egon', 'yuanhao']

map()函数

map函数有映射的作用,即将一个可迭代对象按照指定的规则映射成另一个可迭代对象

map(func,iter1)两个参数,第一个参数func即是映射的规则,第二个参数iter1是要操作的可迭代对象

将names中的元素后边加上"dsb"组成一个新的列表new_names
names = ['alex', 'wupeiqi', 'yuanhao', 'kevin', 'hu老师']
方式一:手动实现
new_names=[]
for name in names:
    new_names.append(name+'dsb')
print(new_names)

方式二:列表生成式
new_names = [name + 'dsb' for name in names]
print(new_names)

方式三:map+匿名函数
res = map(lambda x: x + 'dsb', names)    res得到的是一个经过map函数处理后的一个迭代器对象的内存地址(老母鸡),
print(res)                 输出:<map object at 0x00000164706E8C88>
print(list(res))          输出:['alexdsb', 'wupeiqidsb', 'yuanhaodsb', 'kevindsb', 'hu老师dsb']

在这里提到list()函数它的原理和for循环是一样,从迭代器对象中取值,只不过最后将取出来的值存成列表的形式

reduce() 函数

reduce本意是减少,这里做函数时是合并,将多个合并成一个;在python2中是一个内置函数,在python3中放到了模块中,使用的时候需要在模块中调用,但是用法都是一样的

reduce(function, sequence, initial=None)两个参数,第一个参数是合并规则,第二个参数是序列的意思,其实就是需要一个迭代器对象.

计算1-100的和
方式一:手动实现
res=0
for i in range(101):
    res+=i
print(res)

方式二:列表生成式
print(sum([i for i in range(101)]))

方式三:reduce+匿名函数
from functools import reduce    在python3中需要从模块中调用reduce

print(reduce(lambda x,y:x+y,[i for i in range(101)]))             输出:5050

reduce的第三个参数:初始值

1.在reduce的第二个参数后边其实还可以在设置一个参数,这个参数作为一个初始值存在,比如在这个例子中,首先拿到一个初始值100,再从可迭代对象中取到第一个值,两个值执行合并的函数,然后再依次从迭代器对象中取值执行合并规则,最后得出一个结果,

2.当reduce没有指定初始值时,从可迭代对象中取出的第一值作为初始值,所以reduce不仅仅可以合并数字,同时夜可以合并字符串等一切可以合并的数据类型
print(reduce(lambda x,y:x+y,[i for i in range(101)],100))      输出:5150
print(reduce(lambda x,y:x+y,['h','e','l','l','o'],'----------'))           输出:-----------hello

filter()函数 

filter函数是过滤使用的,将指定的某个值过滤出来
filter(function,iterable)第一个参数是过滤的规则,第二个是要过滤的可迭代对象 ,工作原理就是从可迭代对象中取值,然后按照过滤规则对取出来的值进行过滤,最后得到的是一个迭代器对象(老母鸡),可以使用list(),或者for循环将迭代器对象中的值取出来

names=['alex_dsb','wxx_sb','kevin_sb','hu_sb','egon']
方式一:手动实现
new_names=[]
for name in names:
    if name.endswith('sb'):
        new_names.append(name)
print(new_names)        输出:['alex_dsb', 'wxx_sb', 'kevin_sb', 'hu_sb']

方式二:列表生成式
new_names=[name for name in names if name.endswith('sb')]
print(new_names)       输出:['alex_dsb', 'wxx_sb', 'kevin_sb', 'hu_sb']

方式三:filter+匿名函数
res=filter(lambda name:name.endswith('sb'),names)
print(res)
print(list(res))       输出:['alex_dsb', 'wxx_sb', 'kevin_sb', 'hu_sb']

二、函数的递归和二分法

1. 什么是函数递归
    函数的递归调用是函数嵌套调用的一种特殊形式,
    特殊在调用一个函数的过程中又直接或者间接地调用了该函数本身

    递归本质就是一个循环的过程,
        但是递归必须满足两个原则:
            1. 每进入下一层递归,问题的规模必须有所减少
            2. 递归必须有一个明确的结束条件或者说有一个明确的进入下一层递归的条件
        并且递归有两个明确的阶段
            1. 回溯: 一层一层地递归调用下去
            2. 递推: 再某一层结束掉递归,然后一层一层返回

2, 为何要用递归:
    在某些情况下,基于递归来使用重复的过程比while循环更加简单

3, 如何用

直接调用的方式:

def f1():
    print('from f1')
    f1()
f1()

间接调用的方式:

def f2():
    print('from f2')
    f1()

def f1():
    print('from f1')
    f2()
f1()

递归举例:

问第五个人的年龄,他说比第四个人大两岁,4比3大两岁,3比2大两岁,2比1大两岁,1十八岁
age(5)=age(4)+2
age(4)=age(3)+2
age(3)=age(2)+2
age(2)=age(1)+2
age(1)=18

常规解决办法:

age(n)=age(n-1)+2 # n>1
age(1)=18         # n=1
def age(n):
    if n == 1:
        return 18
    return age(n-1)+2

res=age(5)
print(res)

需求:将list1中的值1-9打印出来:

list1=[1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]]
def func(l):
    for item in l:
        if type(item) is list:
            # 将item当作一个新列表传给功能本身
            func(item)
        else:
            print(item)
func(list1)

二分法: 二分法是算法的一种,算法是如何高效地解决问题的思路

在下边的例子中,从小到大排列的数字列表,判断指定的值在不在列表中,如果使用常规方法,需要将列表中的值一个一个取出来和指定的值进行比对,运气好的话第一个就能找到,但是不幸运的时候就要取到最后一个值才能找到,

使用二分法,首先将数字列表从中间一分为二,判断中间的值和指定的值的关系,然后决定指定的值是在左半部分还是右半部分,然后使用函数的递归,很快就能判断出指定的值在不在列表中

nums=[1,13,15,23,27,31,33,57,73,81,93,94,97,101] # 从小到大排列的数字列表

for num in nums:
    if 58 == num:
        print('find it')
        break
else:
    print('not exists')

nums = [1, 13, 15, 23, 27, 31, 33, 57, 73, 81, 93, 94, 97, 101]  # 从小到大排列的数字列表
def binary_search(find_num,nums):
    print(nums)
    if len(nums) == 0:
        print('not exists')
        return

    # 功能
    mid_index = len(nums) // 2
    if find_num > nums[mid_index]:
        # in the right
        nums=nums[mid_index+1:]
        # 重新运行功能,传入新列表
        binary_search(find_num,nums)
    elif find_num < nums[mid_index]:
        # in the left
        nums=nums[:mid_index]
        # 重新运行功能,传入新列表
        binary_search(find_num,nums)
    else:
        print('find it')

binary_search(97,nums)
binary_search(95,nums)

猜你喜欢

转载自blog.csdn.net/Onion_cy/article/details/82997191