一.高阶函数
1.定义:一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归),满足其一则为高阶函数。
# 参数为函数
def fun():
print('Life is short. You need Python.')
def fun1(fun):
fun()
fun1(fun)
# Life is short. You need Python.
# 返回值为函数
def fun():
def fun1():
print('Life is short. You need Python.')
return fun1()
fun()
# Life is short. You need Python.
2.应用:
- 例:用函数的方法筛选偶数
# 方法一:普通函数法
def even_numbers(list_0):
list = []
for i in list_0:
if i % 2 == 0:
list.append(i)
return list
list = [1, 2, 3,4, 5, 6, 7, 8, 9, 10]
list1 = even_numbers(list)
print(list1)
# [2, 4, 6, 8, 10]
# 方法二:高阶函数法(接受一个或多个函数作为参数)
def even_numbers(fun, list_0): # 将偶数加入新列表,并将其返回
list = []
for i in list_0:
if fun(i):
list.append(i)
return list
def even_number(num): # 单独判断数字是否为偶数
if num % 2 == 0:
return True
return False
list = [1, 2, 3,4, 5, 6, 7, 8, 9, 10]
list1 = even_numbers(even_number, list)
print(list1)
二.匿名函数——lambda函数
1.定义:匿名函数是指一类无需定义标识符(函数名)的函数或子程序。
lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值
2.接受形式:
函数形式 | 意义 |
lambda x,y : x+y | 输入x与y,输出x+y |
lambda x:“yes” if 条件 else “no” | 输入x,若满足条件则输出yes, 否则输出no |
3.应用
- 任意两个数的和
r = lambda a, b: a+b
x = r(1, 2)
print(x)
- 统计偶数(高阶函数法)
def even_numbers(fun, list_0): # 将偶数加入新列表,并将其返回
list_2 = []
for i in list_0:
if fun(i):
list.append(i)
return list_2
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
r = lambda x: True if x % 2 == 0 else False # 将判断函数以匿名函数形式命名
list1 = even_numbers(r, list)
print(list1)
三.闭包
1.定义:
- 将函数作为返回值也是高阶函数我们也称为闭包
- 闭包的好处
- 通过闭包可以创建一些只有当前函数能访问的变量
- 可以将一些私有数据藏到闭包中
- 行成闭包的条件
- 函数嵌套
- 将内部函数作为返回值返回
- 内部函数必须要使用到外部函数的变量
2.闭包的特点:
- 变量不被销毁:函数在运行结束后变量会被销毁掉。如果我们想要将数据保存起来,则需要使用闭包:
def func(num1):
def func_in(num2): # 函数嵌套
x = num1 + num2 # 外层参数调用
print(x)
return func_in # 将内部函数作为返回值返回
f = func(1) # 给num1传一个1
f(2) # 函数调用,给num2传一个2
- 变量不可被更改
def func(num1):
def func_in(num2): # 函数嵌套
num1 = 2
x = num1 + num2 # 外层参数调用
print(x)
print(num1) # 观察num1变化
func_in(1)
print(num1)
return func_in
func(1)
# 1
# 3
# 1
- 闭包中让外部变量可以修改:
def func(num1):
def func_in(num2): # 函数嵌套
nonlocal num1 # 重新将num1赋值
num1 = 2
x = num1 + num2 # 外层参数调用
print(x)
print(num1) # 观察num1变化
func_in(1)
print(num1)
return func_in
func(1)
# 1
# 3
# 2
四.装饰器的引入
1.装饰器的用途:
- 我们可以直接通过修改函数中的代码来完成需求,但是会产生以下一些问题
- 如果修改的函数多,修改起来会比较麻烦
- 不方便后期的维护
- 这样做会违反开闭原则(ocp)
- 程序的设计,要求开发对程序的扩展,要关闭对程序的修改
2.应用
- 装饰fun1()函数
def fun1():
print('我是fun1函数')
def fun():
print('函数开始执行')
fun1()
print('函数执行完毕')
# 函数开始执行
# 我是fun1函数
# 函数执行完毕
- 这样使用装饰器并不能带来更多的简洁,所以我们需要通用装饰器
def fun1():
print('我是fun1函数')
def add(a, b):
return a + b
def fun(fn, *args, **kwargs):
print('函数开始执行')
r = fn(*args, **kwargs)
print(r)
print('函数执行完毕')
fun(add, 1, 2)
fun(fun1)
# 函数开始执行
# 3
# 函数执行完毕
# 函数开始执行
# 我是fun1函数
# None
# 函数执行完毕
五.装饰器的使用
1.装饰器的好处:
- 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
- 在开发中,我们都是通过装饰器来扩展函数的功能的
2.如果每次需要装饰函数的时候,都得重新修改,很是麻烦,所以还要引入@的用法。
语法糖(Syntactic sugar):
计算机语言中特殊的某种语法
这种语法对语言的功能并没有影响
对于程序员有更好的易用性
能够增加程序的可读性
- 简而言之,语法糖就是程序语言中提供[奇技淫巧]的一种手段和方式而已。 通过这类方式编写出来的代码,即好看又好用,好似糖一般的语法。固美其名曰:语法糖
# 通用装饰器
def fun_out(fn, *args, **kwargs):
def fun_inner(*args, **kwargs):
print('函数开始执行')
r = fn(*args, **kwargs)
print(r)
print('函数执行完毕')
return fun_inner
# 需要被装饰的函数
@fun_out # 等价于 f=fun_out(fun)
def add(a, b):
return a + b
# 函数开始执行
# 3
# 函数执行完毕
六.应用练习
- 请使用装饰器实现已存在的函数的执行所花费的时间。
import time
def timer(program):
def fun_inner(num, *args, **kwargs):
print('程序开始')
start_time = time.time()
r = program(num)
print(r)
end_time = time.time()
print('程序结束')
print('耗时:', end_time - start_time)
return fun_inner
@timer
def program(num):
s = 0
for i in range(num):
s += i
return s
program(10000000)
# 程序开始
# 49999995000000
# 程序结束
# 耗时: 1.2097764015197754