天天看点

Python的闭包函数

 闭包函数

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

一、学习闭包函数的必备知识点:
    闭包函数=名称空间与作用域+函数嵌套+函数对象
        核心点:名字的查找关系是以函数定义阶段为准
二、什么是闭包函数?
    闭:封闭关闭,封闭的函数。指的是该函数是内嵌函数,也就是说被麻袋装起来了      
# 封闭的函数实例:
# 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>,)