闭包函数

  基于函数对象的概念,可以将函数返回到任意位置去调用 ,但是作用域的关系是在定义完函数时就已经被确定了的,与函数的调用位置无关。

一、学习闭包函数的必备知识点:
闭包函数=名称空间与作用域+函数嵌套+函数对象
核心点:名字的查找关系是以函数定义阶段为准
二、什么是闭包函数?
闭:封闭关闭,封闭的函数。指的是该函数是内嵌函数,也就是说被麻袋装起来了
# 封闭的函数实例:
# def f1(): # 这里的f1就是麻袋
# def f2(): # 这里的f2就是闭函数
# pass
包:包住,在闭的基础上,指的是该函数f2包含对外层函数f1作用域名字的引用。(不是对全局作用域)
# 闭包函数实例1:
# def f1(): # 这里的f1就是麻袋
# x = 1
# def f2(): # 这里的f2就是闭函数
# print(x) # 这里的x引用到了外层函数,所以此时的f2就是闭包函数
# f2()
# x = 222
# f1() # 1

# 闭包函数实例2:闭包函数之名称空间与作用域+函数嵌套的应用
# def f1(): # 这里的f1就是麻袋
# x = 333333333333333333333
# def f2(): # 这里的f2就是闭函数
# print(x) # 这里的x引用到了外层函数,所以此时的f2就是闭包函数
# f2()
# x = 222
# def foo():
# x = 444
# f1()
#
# foo() # 333333333333333333333

# 闭包函数实例3:
# def f1(): # 这里的f1就是麻袋
# x = 333333333333333333333
# def f2(): # 这里的f2就是闭函数
# print(x) # 这里的x引用到了外层函数,所以此时的f2就是闭包函数
# f2()
# x = 111
# def bar():
# x = 4444
# f1()
# def foo():
# x = 2222
# bar()
#
# foo() # 333333333333333333333

# 闭包函数实例4:闭包函数之函数对象
# 思路:只要我拿到f2的内存地址,那么无论我到哪里调用都可以用到。
# 我想要在全局作用域拿到f2的内存地址。f2就可以在任意的地方调用了。
def f1():
x = 333333333333333333333
def f2():
print("函数f2的x:",x)
# print(f2) # 打印f2的内存地址
return f2 # 这里注意不要加(),不加()拿到了内存地址
# 这里的f是全局变量,但是f的值来自局部,打破了层级上的限制。
f = f1()
# print(f) # 这里我可以获得到f2的内存地址,<function f1.<locals>.f2 at 0x0000025CC8499670>

# 拿到了f2的内存地址后加括号执行得到结果
# f() # 运行结果:函数f2的x: 333333333333333333333

def foo():
x = 555
f()

foo() # 函数f2的x: 333333333333333333333
三、闭包函数的应用场景?(为什么要有闭包函数?)
# 四、两种为函数体传参的方式
# 1、方式一:直接把函数体需要的参数定义成形参,直接传参
# def f2(x):
# print(x)
# f2(1)
# f2(2)
# f2(3)

# 2、方式二:使用闭包函数
# def f1(): # 包的效果
# x = 3
# def f2():
# print(x)
# return f2 # 返回f2的内存地址,把f2内存地址放到全局
#
# f = f1()
# print(f) # 获得到了f2的内存地址:<function f1.<locals>.f2 at 0x0000013A25559670>
# f() # 3

# 把上面的函数写活,修改函数体的参数
def f1(x): # 包的效果
# x = 3 # 这样就写死了,如何写活?
def f2():
print(x)
return f2 # 返回f2的内存地址,把f2内存地址放到全局

f = f1(3)
print(f) # 获得到了f2的内存地址:<function f1.<locals>.f2 at 0x0000013A25559670>
f() # 3
# 爬取三个网址的信息
# import requests
# response = requests.get("https://www.baidu.com")
# print(response.text)
# requests.get(
# print(response.text)
# requests.g
# print(response.text)

# 优化上面代码:写一个下载的功能,
# 传参的方案一:
# import requests
# def get(url):
# # response = requests.get("https://www.baidu.com")
# # print(response.text)
# response = requests.get(url)
# print(len(response.text))
# get("https://www.baidu.com")
# get("h
# get(

# 使用闭包函数:方案二
import requests
def outter(url):
# url='https://www.baidu.com' # 不能写死
def get():
response = requests.get(url)
print(len(response.text))
return get

baidu = outter('https://www.baidu.com') # 拿到outter的内存地址
baidu()

bokeyuan = outte
bokeyuan()

 

# 四、验证closures()函数
x = 1
def outer():
x = 2
def inner():
print(x)
return inner
func = outer()
func() # 2
# 可以通过函数的closure属性,查看到闭包函数所包裹的外部变量
print(func.__closure__)
# (<cell at 0x000002A01FB86B80: int object at 0x00007FFADB77D6C0>,)