递归调用、高阶函数、装饰器
一.递归调用
递归调用: 一个函数自己调用自己, 变成一个循环了,最多一个函数递归调用自己999,作用和运行循环是一样的,区别就是循环是没有次数限制的,递归调用最多999次,超过999次会报错:
递归的特性:
1、 必须有一个明确的结束条件
2、每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3、递归效率不高,少用递归
eg:通过循环,函数自己调用自己
def test1():
while True:
num = int(input('please enter a number:'))
if num%2==0:#判断输入的数字是不是偶数
return True #如果是偶数的话,程序就退出了,返回true
print('不是偶数请重新输入!')
test1() #调用test
eg:通过递归,循环函数多次调用自己
def test1():
num = int(input('please enter a number:'))
if num%2==0:#判断输入的数字是不是偶数
return True #如果是偶数的话,程序就退出了,返回true
print('不是偶数请重新输入!')
return test1()#如果不是偶数的话继续调用自己,输入值
test1()#调用test
二.高阶函数
高阶函数: 如果一个函数的入参是一个函数名的话,这个函数就是高阶函数
函数即变量:虽然是一个函数,但是函数名是一个变量,变量存的是内存地址,指向的是函数体,加上括号了才是函数,那么给函数名重新赋值给一个变量的话,新变量与函数名是一样的,对新的变量名进行调用就和对原函数调用一样
eg:函数即变量的例子
def hello(name):
print(name)
new_hello=hello #hello是一个普通的变量,将hello的值赋值给new_hello,代表的是内存地址
hello('hello...')#hello()调用hello函数
new_hello('newhello..') #new_hello()调用的跟hello()是一样的
eg:高阶函数的例子--入参是函数名就是高阶函数
def add(x,y,z):
res=z(x)+z(y) #函数才可以用z()调用
return res
print(add('99','100',int))#int就是一个函数名
三.装饰器
装饰器:就是函数嵌套加高阶函数,像在打开淘宝购物的时候,哪些模块需要登录才可以操作的话,就需要用到装饰器了。
装饰器作用,在不改变原有函数调用方式入参的情况下,给函数添加新功能,偷偷给函数加上新功能,但是不改变原来的函数
1. 函数里可以嵌套定义函数:但是函数不管在哪都是调用了才会执行,不调用是不会执行的
Eg:函数有内嵌函数,但是没有调用
def warpper():
print('我在外面')
def deco():
print('我在里面')
def hh():
print('我在最里面')
warpper()
返回结果:
我在外面
Eg:函数有内嵌函数,且有调用
def warpper():
print('我在外面')
def deco():
print('我在里面')
def hh():
print('我在最里面')
hh()
deco()
warpper()
返回结果:
我在里面zhang
VVVzhang
2.函数作用域,是就近原则,函数里有的话就先取自己,自己没有的话,就找父级的,父级没有再往外找,查找的原则是从里往外找
# 函数只有被调用才会执行,执行顺序按照函数调用的顺序
Eg: 函数作用域例子
name='luoluo'
def warpper():
print('我在外面%s'%name)
def deco():
name = 'MLing'
print('我在里面%s'%name)
def hh():
print('我在最里面%s'%name)
hh()
deco()
warpper()
3. 装饰器:函数效率不高,查找哪个原因导致效率慢
装饰器作用,在不改变原有函数调用方式入参的情况下,给函数添加新功能,偷偷给函数加上新功能,但是不改变原来的函数
Eg:下面的例子获取函数的运行时间--改变原来的调用方式了 原调用方式run()---后来调用方式run_time(run)
import time
def run():
print('run..')
time.sleep(1)
def run_time(func):
start_time=time.time()
func() #run传给func,func里面就是函数里的代码体,指向run函数里的两行代码
end_time=time.time()
print("run函数运行是",end_time-start_time)
run_time(run)#run代表变量,指向的函数体里的代码,
Eg: 下面的这个函数,其实就是就是返回了一个函数名而已deco函数没调用
import time
def timer(func): #定义一个函数,入参是函数名
def deco(): #再定义个函数,将要给函数新加的功能写进去
start_time = time.time()
func()
end_time = time.time()
print("run函数运行是", end_time - start_time)
return deco #返回这个定义的函数体
def run():
print('run..')
time.sleep(1)
timer(run) #这样调用是没有结果的,因为deco没有调用,所以timer只返回了一个deco函数名
r=timer(run)#其实r=deco
r()#其实就是deco(),是给原来的run函数增加了新功能之后的,但是有改变原来的调用方式,由run()变为了r()
装饰器的处理逻辑:
1、调用timer函数的时候,要传入一个方法名func,timer函数在函数内部定义了一个函数叫做deco
2、deco函数内有新功能,且在函数内部调用了timer里面传入的方法-func()
3、当调timer函数时,返回的是函数体deco,可用函数deco已经把方法-func()要实现的功能都完成了,这个直接运行deco就实现了新功能
4、既然函数deco实现了新功能,函数即变量,给deco重新赋值就行,run=deco的话,run就有了新功能
Eg:装饰器例子1—与上面的例子类似
def run():
print('run..')
time.sleep(1)
import time
def run_time(func):
def deco():
start_time=time.time()
func()
end_time=time.time()
print("run函数运行是",end_time-start_time)
return deco#返回这个定义的函数体
run=run_time(run)
run()
Eg:装饰器例子2---@run_time=run=run_time(run)
import time
def run_time(func):#固定格式
def deco():#固定格式
start_time=time.time()
func()
end_time=time.time()
print("run函数运行是",end_time-start_time)
return deco#固定格式
@run_time #哪个函数用,就放在哪个函数前面
def run():
print('run..')
time.sleep(1)
run()
注意:疑惑的是为什么要内嵌一个函数,就是为了不改变原来函数的调用方式,返回的是函数体,其实就是把新功能封装在了deco这个函数体里面了
def run():
print('run..')
time.sleep(1)
import time
def run_time(func):
def deco():
start_time=time.time()
func()
end_time=time.time()
print("run函数运行是",end_time-start_time)
return deco
run=run_time(run)
print('返回的deco是什么',run)
返回结果:
返回的deco是什么 <function run_time.<locals>.deco at 0x000000F442D8E730>
注意:当函数有入参的话,就需要接收传入函数的参数—下面例子是比较完美的装饰器了,有没有入参都可以
import time,os,sys
def timer(func):
def deco(*args,**kwargs):
#*args,**kwargs用来接收传入函数的参数
start_time = time.time()
res = func(*args,**kwargs)#获取返回值
end_time = time.time()
print('runtime',end_time-start_time)
return res
return deco
@timer
def run2(name):
print(name)
time.sleep(0.5)
run2('niuhanyang')