闭包

python一切皆对象
python中函数

  1. 可做另外一个函数的参数,传递到另外的函数里
  2. 把一个函数当做另一个函数的返回结果

概述

闭包=函数+环境变量

  • 将函数和外部环境变量包在一起做一个封闭,不在受其他外部变量影响
  • 环境变量一定在函数定义时的外部变量(不能是全局变量)
  • 环境变量具有保存记忆的功能
  • 通过闭包可实现在函数外部调用函数内部
1
2
3
4
5
6
7
8
def curve_pre():
a=25 # a在外部环境中,是一个环境变量
def curve(x):
return a*x*x
return curve # 并不只返回函数,同时返回函数和环境变量

f=curve_pre()
print(f(2))
100

闭包保存在closure变量中(检查是否是一个闭包)

1
2
print(f.__closure__)  # 查看f内容
print(f.__closure__[0].cell_contents) # 取出f携带的环境变量

(<cell at 0x0000022214C95D30: int object at 0x00007FF8970CC9A0>,)
25

结论:f返回函数和环境变量

意义
闭包保存的是一个环境,保存了调用的现场,记忆住了上次调用的状态

使用注意事项

1
2
3
4
5
6
7
8
9
10
def f1():
a=10
def f2():
# a此时将被python认为是局部变量,不会影响到外部变量
a=20
print(a)
print(a)
f2()
print(a)
f1()
10 
20
10  #在f2内部对a重新赋值

上面是一个闭包么?

简化一下↓

1
2
3
4
5
6
7
8
def f1():
a=10
def f2():
a=20
return a
return f2
t=f1()
print(t.__closure__) # 检查是否有值,是否是闭包

None

不是闭包,因为f2中的a=20被python认为是局部变量,调用f2时不会引用f1中的环境变量,因此不算是闭包。

只要f2中的a不被赋值即可(可以被引用参与运算)

1
2
3
4
5
6
7
8
def f1():
a=10
def f2():
c=20*a # 是一个闭包
return a
return f2
t=f1()
print(t.__closure__) # 检查是否有值,是否是闭包

实例

一个旅行者从x=0向前走,编写一个函数
x=3 result=3
x=5 result=8
x=6 result=14

关键:每次调用函数时需要保存上次调用函数结果的状态

非闭包: global全局变量

1
2
3
4
5
6
origin=0
def go (step):
global origin
new_pos=origin+step #当函数中找不到origin的值,可到函数外部中寻找origin
origin=new_pos # origin在等号左边时,python会认为这是一个局部变量(解决:将origin改成全局变量)
return origin

闭包:

1
2
3
4
5
6
7
8
9
10
11
12
origin=0
def go_pre(loc): # loc变成了一个环境变量,具有保存记忆功能
def go(step):
nonlocal loc # 声明loc变量不是局部变量,不要在go函数中寻找
new_pos=loc+step
loc=new_pos
return loc
return go
f = go_pre(origin)
print(f(3))
print(f(5))
print(f(6))

3
8
14       

匿名函数

定义:
lambada函数(也称 lambda表达式

1
lambda paramer_list: expression

  • lambda:关键字
  • paramer_list:参数列表
  • expression:表达式(只能是表达式,不能为代码块)
  • 不需要return语句,表达式计算结果即为返回值

调用:
借助赋值给变量调用

1
2
3
4
5
6
# def add(x,y):
# return x+y

f=lambda x,y : x+y
print(f(1,2))
# 并未体现出优势,是个无意义场景

3

附:三元表达式

表达式版本的if,else语句(三元表达式在lambda函数中用处较多)

python版本

条件为真返回的结果 if 条件判断 else 条件为假时的返回结果

其他语言

条件 ? 条件为真返回的结果 : 条件为假返回的结果

栗子:两个数x,y,如果x>y,取x,否则取y

python版本

r= x if x>y else y  

其他语言

r= x > y ? x : y 

map 映射

map(func,*iterables)  # *可变参数
map(函数,(一个或多个)序列(集合))

适用:

对传入的集合/序列的每一个元素都会执行前面的函数,并接收返回的结果,生成一个对象,通过list()函数可以转换出列表
数学角度:映射
将传入的集合经过函数映射出新的集合

map与lambda
将list_x=[1,2,3,4,5]列表中的元素平方后生成新的列表

1
2
3
list_x=[1,2,3,4,5]
list_y=map(lambda x:x*x,list_x)
print(list_y)

[1, 4, 9, 16, 25]

多个参数需注意:

  • 后面列表传入的个数必须和前面lambda函数参数个数相同
  • 最终得到的结果集合中元素的个数取决于传入的元素较少的集合中的元素个数

reduce 归约

from functools import reduce  # 导入模块
reduce(函数,序列,初始值)
  • 原理:连续计算,连续调用函数
  • 函数必须要有两个参数
  • 初始值会在第一次调用lambda函数时参与运算
1
2
3
4
from functools import reduce 
list_x=[1,2,3,4,5]
r=reduce(lambda x,y:x+y,list_x)
print(r)
15
  • 首次调用列表前两个元素作x,y
  • 第二次调用取第一次调用结果为第一个参数,取第三个元素为第二个参数
  • 第三次调用将结果作第一个参数,取下一个元素为参数
  • 实质为“对序列求和”

filter 过滤

filter(函数,序列)

栗子:过滤出list_x=[1,0,1,0,0,1]中的1

1
2
3
list_x=[1,0,1,0,0,1]
r=filter(lambda x:True if x==1 else False,list_x)
print(list(r))

[1,1,1]
  • 返回的lambda函数必须存在if,else语句
  • 如果返回True保留,返回False删除

高级:过滤大小写

r=filter(lambda x:True if x>='A'and x=<'Z' else False,list_x)

命令式编程 与 函数式编程

命令式编程组成
def
if else
for

函数式编程组成
lambda(算子):可替换def
map,reduce:可替换循环