闭包
1. 函数对象
精髓: 可以把函数当成变量去用
函数名和变量名一样,都是指向的是内存地址
2. 函数名的用途
2.1 可以赋值
把一个函数名赋值给另一个变量名
# func=函数的内存地址
def func():
pass
f=func
print(func) # <function func at 0x000001E78F9B3EA0>
print(f) # <function func at 0x000001E78F9B3EA0>
2.2 当参数
函数名也可以当做参数传给另一个函数
def func():
pass
def foo(×): #× = func的内存地址#
print(x)
x()
foo(func) #foo( func的内存地址)
2.3 当返回值
函数名也可以当做函数的返回值
def func():
pass
def foo(x):
return x
res = foo(func)
print(res)
2.4 当参数
函数名可以当做容器类型的一个元素
def func():
print('func函数: ',func)
l=[func,]
print(l)
l[0]() # 调用func函数
dic={ 'k1' :func}
print(dic)
dic['k1']() # 调用func函数
2.5 小练习
def login():
print('登录功能')
def transfer():
print('转账功能')
def check_balance():
print('查询余额')
def change_password():
print('修改密码')
# 巧用数据类型
dic = {
# '1': login,
'0': ('退出', None),
'1': ['登录', login],
'2': ['转账', transfer],
'3': ['查询余额', check_balance],
'4': ['更改密码', change_password],
# '2': transfer,
# '3': check_balance,
}
while 1:
for key, value in dic.items():
print('{} {}'.format(key, value[0]))
choice = input('请输入编号:').strip()
if not choice.isdigit():
print('必须输入编号,憨批')
continue
if choice == '0':
break
if choice in dic:
dic[choice][1]()
else:
print('你输入的命令不存在,憨批')
3. 函数的嵌套
3.1 函数的嵌套调用
在调用一个函数的过程中又调用其他的函数
def func1():
print("调用了func1函数")
def func2():
print("调用了func2函数")
def func3():
print("调用了func3函数")
def func():
func1()
func2()
func3()
应用场景 :
# 把各个小功能(小函数),封装到一个大功能(大函数)里面
def max2(x, y):
return x if x > y else y
# 比较4个参数的大小
def max4(a, b, c, d):
# 比较a,b得到res1
res1 = max2(a, b)
# 比较res1,c,得到res2
res2 = max2(res1, c)
# 比较res2,d ,得到res3
res3 = max2(res2, d)
return res3
print(max4(7838237, 9859, 949, 90))
3.2 函数的嵌套定义
在函数内定义其他的函数
def func():
def func1():
pass
# 举例:
# 求圆的周长和面积,但是只在圆内调用,在其他地方不用
from math import pi
def circle(radius, action=None):
"radius:半径 action为0是求周长 action为1是求面积 "
def get_perimeter(radius):
return 2 * radius * pi
def get_area(radius):
return pi * radius ** 2
# 求圆的周长
if action == 0:
return get_perimeter(radius)
# 求圆的面积
elif action == 1:
return get_area(radius)
上面的应用场景比较少,函数的嵌套定义更多的用在闭包
# 函数的嵌套定义你可以认为把一堆函数丢到一个大容器(最外面的那个函数)中
# 同时在外部是无法访问这个函数的,只能在大容器中访问这些函数
4. 闭包函数
闭包函数也可以直接简称为闭包
# 闭包函数 = 名称空间与作用域 + 函数嵌套 + 函数对象
# 核心点: 名字的查找关系是以函数定义阶段为准
4.1 什么是闭包函数
# "闭"函数指的是该函数为内嵌函数 是定义在一个函数内的函数
def f1():
def f2(): # f2是闭函数
pass
# "包是在闭的基础上"
# "包"函数指的该函数包含对外层函数(第几层无所谓)作用域名字的引用(不是对全局作用域)
def f1():
x = 111
def f2():
print(x) # x就是包,f2从外层函数f1那里引用
闭包函数 : 名称空间与作用域 + 函数嵌套
def f1():
x = 222
def f2():
print(x)
f2()
x = 111
def foo():
x = 333
f1()
foo() # 打印2222
闭包函数 : 名称空间与作用域 + 函数嵌套 + 函数对象
def f1():
x = 33333333333333333333
def f2():
print('函数f2:', x)
return f2 # 这样一搞就有了骚操作,在全局能够访问到f2的内存地址了,就打破了
# 以前在外部无法访问局部的值了
f = f1()
# f是全局的,但是f的值是局部的
# 牛逼之处你在全局拿到了在局部作用域的名字
# 牛逼的实现了,在任意地方都能访问到局部的值了,打破了层级限制
# 拖家带口的返回,每次你调用里面的x都是在局部定义的那个x
4.2 为什么要有闭包
为什么要有闭包换句话说就是闭包的应用场景有哪些?
闭包实现了函数的另一种传参方式,虽然没有直接传参那种看上去更加简单,但是有的应用场景就是直接传参
解决不了,那么你不要忘记还有一种闭包传参
的方式
# 先写x=3和函数f2的定义,然后用f1包起来
def f1():
x = 3
def f2():
print(x)
return f2
f = f1() #此时f指的就是f2的内存地址
# 你可以写f,那么你也可以写成f2
# f2 = f1()
# 有的人就说了 你写成x=3不是写死了吗,那么我们可以这样写
def f1(x):
def f2():
print(x)
return f2
# f = f1(1)
# f = f1(2)
# f = f1(3) # 这样就做到了 你传几,就是几
5. 两种传参方式
一种就是直接传 还有一种就是通过闭包传
学习闭包就是学习了另一种函数传参方式,(曲线救国),当你有一中需求是函数直接
传参解决不了的时候,不要忘记还有闭包这种这种传参方式,下面介绍的装饰器就是
你无法直接传参,只能通过闭包传参来解决