1.递归函数:
1.1含义:
如果一个函数在内部不调用其他函数,而是调用它本身的话,这个函数就是递归函数
1.2条件:
1.必须有一个明确的结束条件--递归出口
2.每进行更深一层的递归,问题规模相比上次递归都要有所减少
3.相邻两次重复之间有紧密的联系
1.计算1+2+3+...+100的和
def add(n):
if n == 1:
return 1
else:
return n+add(n-1)
print(add(100))
2.计算斐波那契数列(1,1,2,3,5,8...)
def funa(n):
if n==1 or n==2:
return 1
return funa(n-1)+funa(n-2)
print(funa(7))
1.3优点:简洁,逻辑清晰,解题更具有思路
1.4缺点:使用递归函数的时候,需要反复调用函数,耗内存,运行效率低
2.闭包
含义:在嵌套函数的前提下,内部函数使用了外部函数的变量,而且外部函数返回了内部函数,我们就把使用了外部函数变量的内部函数称为闭包
2.1条件:
1.嵌套函数(函数里面在定义函数)
2.内层函数使用外层函数的局部变量
3.外层函数的返回值是内层函数的函数名(注意:返回函数名,而不是inner(),是因为inner函数里参数比较多或者说受到限制时,写法不太规范)
def outer():
n = 10
def inner():
print(n)
return inner
print(outer()) #<function outer.<locals>.inner at 0x000002405D04B0D8> 返回内部函数的地址
#调用内函数的第一种写法
outer()() #10
#调用的第二种写法
ot = outer() #调用外函数
ot() #调用内函数
带参数的情况
def outer(m):
n = 10
def inner(o):
print(m+n+o)
return inner
outer(20)(10)
ot = outer(20)
ot(10)
2.2函数引用
函数名里保存了函数所在位置的引用(就是地址)
a = 1 #a只不过是一个变量名,存的1这个数值所在的地址,就是a里面存了数值1的引用
print(a) #1
print(id(a)) #140719332688144
print(id(1)) #140719332688144
a = 2 #修改a,生成新的值从新赋给变量a
print(id(a)) #140719332688176内存地址发生了改变
def test(): #test也只不过是一个函数名,里面存了这个函数所在位置的引用
print('这是test函数')
test()
print(test) #内存地址(引用)<function test at 0x0000017B51DC2F78>
te = test
te() #通过引用调用函数
2.3每次开启内函数都在使用同一份闭包变量
总结:使用闭包的过程中,一但外函数被调用一次,返回了内函数的引用,虽然每次调用内函数,会开启一个函数,执行后消亡,但是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量。
def outer(m):
print("outer函数中的值",m)
def inner(n):
print("inner函数中的值",n)
return m+n
return inner
ot = outer(10)
print(ot(20)) #30
print(ot(50)) #60
print(ot(80)) #90
3.装饰器
3.1.含义:
装饰器本质上是一个闭包函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
3.2.作用:在不改变原有代码情况下给函数添加额外的功能
3.3.条件:
1.不修改源程序或函数的代码
2.不改变函数或程序的调用方法
不用装饰器的方式添加新的功能1.直接添加,2.引入参数
def test1(fn):
print("读书")
print("吃饭")
fn()
def test2():
print("看电视")
test1(test2)
3.4标准版装饰器
将原有函数名重新定义为以原函数为参数的闭包
#被修饰的函数
def send():
print("发短信")
def outer(fn): #外层函数,fn是形参
def inner(): #内函数
print("登录")
fn() #send() 执行被修饰的函数
return inner
print(outer(send)) #内层函数地址
outer(send)() #调用内层函数
3.5语法糖
格式:@装饰器名称
def outer(fn): #外层函数,fn是形参
def inner(): #内函数
print("登录")
fn() #send() 执行被修饰的函数
return inner
@outer #注意装饰器名称后面不要加上(),前者是引用,后者是返回该函数要返回的值(最好顶格写不要空行)
def send():
print("发短信")
send() #登录 发短信
@outer
def send2():
print("刷抖音")
send2() #登录 刷抖音
3.6被装饰的函数有参数
3.6.1标准版:
def outer(fn): #外层函数,fn是形参
def inner(name): #内函数
print(f"{name}是inner中的参数")
fn() #func() 执行被修饰的函数
return inner
def func():
print("这是被装饰函数")
print(outer(func)) #内层函数地址
outer(func)('panda') #调用内层函数
def outer(fn): #外层函数,fn是形参
def inner(name): #内函数
print(f"{name}是inner中的参数")
fn(name) #func() 执行被修饰的函数
return inner
def func(name):
print("这是被装饰函数")
print(outer(func)) #内层函数地址
outer(func)('panda') #调用内层函数
3.6.2语法糖
def outer(fn): #外层函数,fn是形参
def inner(name): #内函数
print(f"{name}是inner中的参数")
fn(name) #func() 执行被修饰的函数
return inner
@outer
def func(name):
print("这是被装饰函数")
func('panda')
3.7被装饰函数有可变参数*args ,**kwargs
def outer(fn): #外层函数,fn是形参
def inner(*args,**kwargs): #内函数
print("登录")
fn(*args,**kwargs) #func() 执行被修饰的函数
return inner
def func(*args,**kwargs):
print(args)
print(kwargs)
print(outer(func)) #内层函数地址
ot = outer(func) #调用外层函数
ot('panda',friend='monkey',name='bear') #登录 ('panda',) {'friend': 'monkey', 'name': 'bear'}
*args:接收元组的形式,**kwargs:接收字典的形式
3.8多个装饰器
多个装饰器的装饰过程,离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程
def deco1(fn):
def inner():
return "lucky "+fn()+" day"
return inner
def deco2(fn):
def inner():
return "good "+fn()+" study"
return inner
@deco1
@deco2
def test():
return "学python"
print(test()) #lucky good 学python study day
@deco2
def test():
return "学python"
print(test()) #good 学python study
@deco2
@deco1
def test():
return "学python"
print(test()) #good lucky 学python day study