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("https://www.cnblogs.com/liunaixu/")
# print(response.text)
# requests.get("https://www.cnblogs.com/linhaifeng/")
# 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("https://www.cnblogs.com/liunaixu/")
# get("https://www.cnblogs.com/linhaifeng/")

# 使用闭包函数:方案二
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 = outter('https://www.cnblogs.com/liunaixu/')
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>,)
复制代码

 

 
posted @   思江  阅读(1334)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示