高阶函数
什么是高阶函数
1,接收的参数,是一个函数名(是一个函数的引用)
2,函数的返回值,是一个函数名
满足任一条,就是高阶函数
情况一
""" 高阶函数之,函数接收的参数是一个函数名 """ def eat(): print('吃肉') def func(f): # f = eat f() # eat() func(eat)
情况二
""" 高阶函数之,函数的返回值是一个函数名 """ def run(): print('在跑') def eat(): print('吃肉') return run r = eat() # r = run r() # run()
函数名的本质
函数名本质就是一个标识符
函数体才是函数的本体
函数名会指向函数本体
如果把一个函数名赋值给另一个变量
那么通过这个变量加上括号
也可以调用函数
函数的嵌套
函数里面定义函数
""" 函数的嵌套 """ def cat(): def run(): print('在跑') run() cat()
闭包
首先给出闭包函数的必要条件:
-
闭包函数必须返回一个函数名
-
闭包函数返回的那个函数必须引用父级函数变量(一般不能是全局变量)
闭包
1,它是一个高阶函数
因为外部的函数返回值是一个函数名(内部函数)
2,它是一个函数的嵌套
外部函数里面又定义了内部函数
3,内部的函数要用到外部函数的局部变量
闭包模型
def outer(): name = "张三" def inner(): print(name) return inner # 高阶函数 m = outer() m()
局部变量的两种形态
局部变量的特点
生命,从函数执行,到函数结束
形态1,函数内部直接通过赋值方式定义的变量
它就是一个局部变量
本例中的age就是一个函数中的局部变量
def func(): age = 18 print(age) func()
形态2,通过形参方式接收的数据也是局部变量
本例中的age就是一个局部变量
实参的数据赋给形参的过程
就相当于,在函数的内部定义
age = 18
最终的效果和形态一是一样的
def func(age): print(age) func(18)
外部函数带参数的闭包
def outer(name): # name = "吕布" def inner(): print(name) return inner m = outer("吕布") m()
三层函数闭包
def func(): name = "李白" def outer(name): def inner(): print(name) return inner return outer name = "赵云" f = func() o = f(name) o()
def func(age): def outer(name): def inner(): print(name) print(age) return inner return outer f = func(18) o = f("刘备") o()
新增的需求
为函数统计耗时
# 一个已经开发好的项目 # 需要拓展功能 # 要求每一个函数在执行后 # 都输出一下耗时 # # 如何解决 def add_many_num(): isum = 0 for i in range(100000): isum += i print(isum) add_many_num()
解决一
# 方案1 # 在函数内加入功能 import time def add_many_num(): start = time.time() isum = 0 for i in range(100000): isum += i print(isum) end = time.time() print('耗时', end-start) add_many_num() # 问题 # 修改了函数内部的代码,容易造成报错
解决2
# 方案2 # 利用高阶函数 # 不修改原来的代码 import time def add_many_num(): isum = 0 for i in range(100000): isum += i print(isum) def outer(func): start_time = time.time() func() end_time = time.time() print('耗时', end_time - start_time) # outer(add_many_num) add_many_num() # 问题 # 功能解决了,但是函数的调用方式变了 # 如果要运行拓展了功能的函数,必需修改调用方式
装饰器
装饰器的本质就是一个函数
语法糖
语法糖(Syntactic sugar): 计算机语言中特殊的某种语法 这种语法对语言的功能并没有影响 对于程序员有更好的易用性 能够增加程序的可读性
简而言之,语法糖就是程序语言中提供的一种手段和方式而已。 通过这类方式编写出来的代码,即好看又好用,好似糖一般的语法。固美其名曰:语法糖
格式
@dec
def func():
pass
相当于执行了下面的代码
func = dec(func)
调用方式不改变
func()
装饰器的进阶
位置不正确时
# 会报错的情况 # 装饰器写在了后面 import time @outer #add_many_num = outer(add_many_num) def add_many_num(): isum = 0 for i in range(100000): isum += i print(isum) def outer(func): def inner(): start_time = time.time() func() end_time = time.time() print('耗时', end_time - start_time) return inner add_many_num()
装器形态还原
需要明确
只要解释器读到了装饰器所定久的函数那一行
就会自动的执行一下一个代码。。。。
# 会报错的情况 # 装饰器写在了后面 import time def outer(func): print('.....') def inner(): start_time = time.time() func() end_time = time.time() print('耗时', end_time - start_time) return inner @outer # 相当于 add_many_num = outer(add_many_num) def add_many_num(): isum = 0 for i in range(100000): isum += i print(isum) add_many_num()
被修饰的函数有返回值时
""" 有一个参数的时候 """ import time def outer(func): def inner(name): start_time = time.time() res = func(name) end_time = time.time() print('耗时', end_time - start_time) return res return inner @outer # 相当于 add_many_num = outer(add_many_num) def add_many_num(name): isum = 0 print(name) for i in range(100000): isum += i print(isum) return 'ok' res = add_many_num("周泰") print(res)
复习多值传参
def func(*args, **kwargs): print('hello') print(args,type(args)) print(kwargs,type(kwargs)) func(1,2,3, name="张三", age=18)
拆包复习
拆包元组
函数调用的时候
def func(a,b): print(a,b) t = (1,2) func(*t) #func(1,2) # func(1,2)
拆包字典
函数调用的时候
def func2(name=3): print(name) d = {"name":"zs"} func2(**d) # func2(name="zs")
函数转发多值传参
args元组
形态1
def func2(a,b): print('a',a) print('b',b) def func1(): t = (1,2) func2(*t) # func2(1,2) func1()
形态2
def func2(a,b): print('a',a) print('b',b) def func1(*t): # t = (1,2) func2(*t) # func2(1,2) func1(1,2)
kwargs字典
def func2(name="张飞"): print(name) def func1(**kwargs): # kwargs = {"name" : "吕布"} func2(**kwargs) # func2(name = "吕布") func1(name = "吕布")
万能装饰器
需要牢记的
def outer(func): def inner(*args, **kwargs): print('前面的') res = func(*args, **kwargs) print('后面的') return res return inner
多层装饰器
理解装饰顺序
"""
双层装饰器体验
"""
import time
def outer(func):
@timer # inner = timer(inner)
def inner(*args, **kwargs):
print('前面的')
res = func(*args, **kwargs)
print('后面的')
return res
return inner
def timer(func):
print('.....')
def inner():
start_time = time.time()
func()
end_time = time.time()
print('耗时', end_time - start_time)
return inner
@timer # xxx = timer(xxx)
@outer # add_n_num = outer(add_n_num)
def add_n_num():
n = 0
for i in range(100000):
n += i
print(n)
add_n_num() # inner()