关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数)。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包
函数对象
精髓:把函数当成变量用(因为书写时多次运行所以案例返回的内存地址不相同),也可以像变量一样当做函数参数或者函数返回值使用
# 定义函数其实是 func 指向 函数存储的内存地址
def func():
print('from func')
# 1.可以赋值
f = func # 注意:没有括号(有括号是函数的返回值赋值给f)
print(id(f),id(func)) # 14645184 14645184 内存地址相同
f() # from func 也可以调用f函数,效果相同
# 2.可以把函数当做参数,把对应的内存地址传给另一个函数
def foo(x):
print(x) # <function func at 0x019677C0>
x() # from func 可以加括号执行
foo(func) # 其实传输的是函数的内存地址
# 3.可以把函数当做另一个函数的返回值
def foo1(x):
return x
res = foo1(func)
print(res) # <function func at 0x02208460>
res() # from func
# 4.可以当做容器类型的元素
l = [func,]
l[0]() # from func
dic = {'k1':func}
dic['k1']() # from func
函数对象的案例
修改ATM登录案例
# coding:utf-8
def login():
print('登录功能')
def transfer():
print('转账功能')
def check_banlance():
print('查询余额')
def catalogue():
# 读取func_dic来生成显示列表 -> 方便程序后期快速修改
list = 0
for name in func_dic:
print('{} -> {}'.format(list,func_dic[name][0]))
list += 1
func_dic = {
# 程序运行过程中只有读的需求所以用元组
'0':('退出',None), # 为了规范格式使用None
'1':('登录',login), # 这里就是函数对象的应用
'2':('转账',transfer),
'3':('查询',check_banlance)
}
while True:
catalogue() # 显示列表
choic = input('请输入命令编号:').strip()
if not choic.isdigit():
print('输入有误')
continue
if choic == '0':
break
if choic in func_dic:
func_dic[choic][1]()
else:
print('输入有误')
函数嵌套
函数嵌套在名称空间的‘嵌套关系’里面已经介绍过了
函数嵌套本质目的是为了将大功能再次才分为多个小功能,再由大功能调用小功能
函数嵌套调用:在函数中调用其他函数
def func():
func1() # func函数中调用func1
def func1():
pass
func()
案例:四个值查找最大值
def max(a,b):
'''比较两个数大小'''
if not a<b:
# not a<b == a>b and a == b
return a
else:
return b
def max4(a,b,c,d):
res = max(a,b)
res = max(res,c)
res = max(res,d)
return res
res = max4(1,5,3,4)
print(res)
函数嵌套定义:在函数内定义其他函数
把f1当做容器,全局无法调用f2
def f1():
# f2存在于f1的局部名称空间,只能在f1内调用
def f2():
pass
f2()
案例:求圆周面积
def circle(radius,action=0):
'''求圆周长 (radius=半径长度,action=0求周长/1求面积)'''
from math import pi
def perimiter(radius):
return 2*pi*radius
def area(radius):
return pi*(radius**2)
if action==0:
return perimiter(radius)
elif action==1:
return area(radius)
res = circle(5,1)
print(res)
闭包函数
闭包函数=名称空间与作用域+函数嵌套+函数对象
什么是闭包函数?
‘闭’:该函数是内嵌函数
‘包’:该函数包含对外层函数(不是全局函数)作用域名字的引用
def f1():
x = 333
def f2():
print('函数f2:',x)
return f2
f = f1() # 在全局拿到f2的内存地址
print(f) # <function f1.<locals>.f2 at 0x00AF85C8>
f() # 函数f2: 333
使用函数对象的概念,将处于嵌套函数内部的f2函数变成了全局函数f
但,无论在哪儿调用f,都不会改变f的状态
闭包案例
使用包requests(模仿浏览器进行http访问的模块)
pip install requests
传参爬网站html
import requests
# 方案一:传参 - 通过参数方式为函数体传值
def get(url):
response = requests.get(url)
print(response.text)
get('https://kinghtxg.github.io')
# 方案二:闭包 - 通过闭包的方式为函数体传值
def get(url):
def get_url():
response = requests.get(url)
print(response.text)
return get_url
baidu = get('https://www.baidu.com')
baidu()
blog = get('https://kinghtxg.github.io')
blog()