python:递归函数、偏函数、匿名函数

递归函数:
一个函数在内部调用自身,这个函数就被成为递归函数


无穷递归:

例1:

def func_1():
	return func_1()
1、从理论上来讲,上面这段代码将永远执行下去直至耗尽所有的内存资源。这类递归被称作无穷递归,理论上永远不会结束。

2、在python3中出于"善意的保护",对无穷递归的深度默认限制为100层,所以最后代码才会自动停下来。当然我们也可以自己设置递归深度

import sys
sys.setrecursionlimit(1000)#将递归深度设置为1000层
递归的条件:
1、调用函数本身
2、设置了正确的返回条件

递归的特点:

1、递归就是就是在函数里调用调用自身
2、在使用递归时,必须有一个明确的结束条件(称为递归出口)
例2:
#求5的阶乘(非递归版)
def func(n):
    result = n
    for i in range(1,n):    #多次引用变量n	
        result *= i
    return result
print(func(5))
例3:
#递归版本
def func(num):
    if num == 1:
        return 1
    return num * func(num - 1)
print(func(5))
#上面代码的输出结果为120
#当num = 5时,返回4 *func(4)
#当num = 4时,返回5*4 *func(3)
#当num = 3时,返回5*4 *3*func(2)
#当num = 2时,返回5*4 *3*2*func(1)
#当num = 1时,返回5*4 *3*2*1
备注:
1、理论上所有递归函数都可以写成循环的方式,不过循环的逻辑不如递归清晰
2、在使用递归函数时需要防止栈溢出。在计算机中,函数的调用是通过栈(stack)这种数据结构实现的。每当进入一个函数调用,栈就会加一层栈帧;每当函数返回,栈就会减少一层栈帧。由于栈的大小不是无限的,因此递归调用的次数过多就会导致栈溢出。解决栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果一样,把循环看成一种特殊的尾递归函数也可以。
3、尾递归是指在函数返回时调用函数本身,并且return语句不能包含表达式。这样编译器或解释器就可以对尾递归进行优化,使递归本身无论调用多少次都只占用一个栈帧,从而避免栈溢出的情况
例4:
def func_1(n):
	return func_2(n,1)
	
def func_2 (num,product):
    if num == 1:
        return product
    return func_2(num - 1,num * product) #调用func2函数本身,且return语句不含表达式
print(func_1(5))


匿名函数:

python使用lambda来创建匿名函数。所谓匿名,即不再使用 def 语句这样标准的形式定义一个函数。
1、lambda只是一个表达式,函数体比def简单很多。
2、lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
3、lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
语法:
lambda [arg1 [,arg2,.....argn]]:expression
1、[arg1 [,arg2,.....argn]]为函数的参数:可以有多个参数,可以使用默认参数
2、冒号":"为分隔符:分隔符左边为参数,右边为表达式
3、expression为表达式:即返回值。lambda函数中不能有return 

例5:

function = lambda x,y,z = 3:x +y + z #如果不输入就使用默认参数
print(function(1,2))
#输出结果为:6
适合使用匿名函数的情况:
1、程序一次性使用,不需要定义函数名时,用匿名函数可以节省内存中变量定义空间
2、如果想让程序更加简洁,使用匿名函数就可以做到

匿名函数的规则:
1、一般有一行表达式,必须有返回值
2、不能有return
3、可以没有参数,也可以有一个或多个参数

拓展:求一个列表中大于3的元素

例6:

#程式编程
list_1 = [1,2,3,4,5]
list_2 = []
for num in list_1:
    if num > 3:
        list_2.append(num)
print(list_2)
#上面代码的输出结果为[4,5]

例7:

def func(x):   #判断函数
    return x > 3
	
list_1 = filter(func,[1,2,3,4,5])
list_1 = list(list_1)  #此时list_1为一个对象,无类型,需要将其定义为一个列表,若不定义则返回结果为<filter object at 0x7f5e4661dcc0>

print(list_1)
#上面代码的输出结果为[4,5]
备注:
1、filter( )函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
2、在python2中filter返回的是一个列表(list),可以直接使用它。但在python3中filter返回的并不是一个list,而是一个filter对象(可迭代对象)
filter() 方法的语法:
filter(function, iterable)
function -- 判断函数。
iterable -- 可迭代对象
例8:
#使用匿名函数
print(list(filter(lambda x :x > 3,[1,2,3,4,5])))
#上面代码的输出结果为[4,5]


偏函数:

扫描二维码关注公众号,回复: 2746495 查看本文章
1、偏函数是 将所要承载的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数后续的参数,除非使用关键字参数.
2、当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单.
3、简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

4、函数在执行时,要带上所有必要的参数进行调用。但是,有时参数可以在函数被调用之前提前获知。这种情况下,一个函数有一个或多个参数预先就能用上,以便函数能用更少的参数进行调用。

5、partial函数的作用就是:将所作用的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数的后续参数,原函数有关键字参数的一定要带上关键字,没有的话,按原有参数顺序进行补充。

例9:

from functools import partial
def func(m,n):
    return m % n
new_func = partial(func,100)   #new_func为一个函数
print("调用自定义函数时,结果为:",func(100,7))
print("调用偏函数时,结果为:",new_func(7))  #默认传入到第一个参数m

#调用自定义函数时,结果为: 2
#调用偏函数时,结果为: 2

例10:

import functools
int2 = functools.partial(int, base=2)

print(int2('1000000'))
print(int2('1010101'))

#输出结果我为:64、85

例11:

from functools import partial  
def func(m,n):  
    return m % n  
new_func = partial(func, n = 100)   #new_func为一个函数,指定n = 100
print("调用自定义函数时,结果为:",func(7,100))
print("调用偏函数时,结果为:",new_func(7))

#调用自定义函数时,结果为: 7
#调用偏函数时,结果为: 7

例12:

from functools import partial as pto
def func(a, b = None):
    if b is None:
        return a + 10
    return a + b

add = pto(func, 10)
print(add(10))

add = pto(func, 10, 20)
print(add())
#20、30

例12:

from functools import partial
import tkinter
root = tkinter.Tk()
mybutton = partial(tkinter.Button,root,fg = 'white',bg = 'blue')
b1 = mybutton(text = 'Button1')
b2 = mybutton(text = 'Button2')
qb = mybutton(text = 'QUIT',bg = 'red',command = root.quit)
b1.pack()
b2.pack()
qb.pack(fill = tkinter.X,expand = True)
root.title('PAF!')
root.mainloop()

拓展

1、求一个数字序列中所有元素相乘的值

def func(x):
    result = 1     #创建一个初始变量(值),相当于一个中间值
    for num in range(1,x):
        result *= num
    return result
print(func(5))
#上面代码输出结果为:24(初始变量的值会影响到最后的输出结果,所以初始值得选取一定要慎重)
2、求一个数字序列中所有元素相加的值
def func(x):
    result = 0
    for num in range(1,x):
        result += num
    return result
print(func(5))
#上面代码的输出结果为:10
3、求一个无序序列中所有元素相加的值
list = [1,10,3,4]

def func_2():
    x = 0
    for num in list:

        x += num
    return x
print(func_2())
#上面代码的输出结果为:18

备注:使用range()函数生成序列时,生成的序列不会包含结束的元素(包左不包右),若我们想一起计算最右边数时,可以将初始值设置为最右边的数

例1:

def func(x):
    result = 5
    for num in range(1,x):
        result += num
    return result
print(func(5))  #输出结果为15
例2:
def func(x):
    result = 5
    for num in range(1,x):
        result *= num
    return result
print(func(5))   #输出结果为120

例3:

list = [1,10,3,4]

def func_2():

    for num in list:

        num += num
    return num
print(func_2())
#上面代码的输出结果为:8,即不设置初始值时,会执行完for循环后再执行加法(此时num的值为4,在上一篇文章中说所的python循环中不包含域)

猜你喜欢

转载自blog.csdn.net/qq_39314932/article/details/80587968