【python基础之函数对象和闭包】 --- 函数对象与闭包
1.【python入门之相关语言了解】---开发语言与其他2.【python入门之pycharm篇】--如何安装pycharm以及如何安装python解释器3.【python工具指南】pycharm相关快捷键---windows+mac合集4.【python入门之pip换源问题】---pip换源的方式5.【python小记】---PE8规范简述6.【python入门之虚拟环境与系统环境】---虚拟环境的创建方式及使用7.【python入门之常量与变量】---常量与变量小记8.【python入门之基本数据类型的学习】---基本数据之数字类型9.【python入门之基本数据类型的学习】---基本数据类型(列表、字符串)【二】10.【python入门之基本数据类型】---基本数据类型(字典、布尔)【三】11.【python入门之基本数据类型】---基本数据类型(元组、集合)【四】12.【python入门之程序与用户交互】---程序与用户交互13.【python入门之基本运算符】---基本运算符14.【python入门之流程控制语句】---流程控制语句15.【python入门之垃圾回收机制】---python 垃圾回收机制16.【python入门之文件操作】---文件操作17.【python入门之文字符编码】---字符编码18.【python基础之可变和不可变数据类型】---python之栈的介绍19.【python基础之可变和不可变数据类型】--- python之堆的介绍20.【python基础之可变和不可变数据类型】--- python堆栈的相关应用21.【python基础之数据类型的内置方法】--- 数据类型的内置方法22.【python入门之深浅拷贝】---python 深浅拷贝23.【python入门之异常处理】---python 异常处理24.【python基础之函数】--- 函数入门25.【python基础之命名空间与作用域】---命名空间与作用域
26.【python基础之函数对象和闭包】 --- 函数对象与闭包
27.【python基础之装饰器】---装饰器28.【python基础之迭代器】 --- 迭代器29.【python基础之三元表达式】--- 三元表达式30.【python基础之列表生成式】---列表生成式31.【python基础之生成器】---生成器32.【python基础之模块介绍】---模块33.【python基础之包介绍】---包34.【python扩展之软件开发目录规范】---软件开发目录规范35.【python常用模块之OS模块简介】---OS模块36.【python常用模块之random模块简介】---random模块37.【python常用模块之time时间模块】---时间模块(time/datetime)38.【python常用模块之subprocess模块】---subprocess模块39.【python常用模块之sys模块】---系统模块(sys)40.【Python常用模块之logging模块】---日志输出功能(示例代码)41.【python--- ATM+SHOPPING】42.【python基础之面向对象介绍】--- 面向对象43.【python基础之面向对象的绑定方法与非绑定方法】--面向对象的绑定方法与非绑定方法44.【python网络编程相关】 ----操作系统相关了解45.【python之DRF学习】DRF入门了解46.【python之DRF学习】三大方法之认证47.【python之接口工具】利用docker-compose搭建Yapi48.【python之DRF学习】drf全局异常49.【python之DRF学习】 drf之接口文档介绍及使用50.【python之DRF学习】drf之jwt使用【一】函数对象
-
函数对象指的是函数可以被当做
数据
来处理 -
具体可以分为四个方面的使用
· 函数可以被引用
·函数可以作为容器类型的元素
·函数可以作为参数传入另外一个参数
·函数的返回值可以是一个函数
【1】函数可以被引用
# 定义一个函数
def add(x, y):
return x + y
# 将函数地址绑定给一个变量
func = add
# 通过这个变量找到对应的地址,从而调用函数
res = func(1, 2)
print(res) # 3
【2】函数可以作为容器类型的元素
def add(x, y):
return x + y
dic = {'add': add, 'max': max}
print(dic) # {'add': <function add at 0x0000020523843E20>, 'max': <built-in function max>}
res = dic['add'](1, 2)
print(res) # 3
【3】函数可以作为参数传入另外一个参数
def add(x, y):
return x + y
def foo(x, y, func):
return func(x, y)
res = foo(1, 2, add)
print(res) # 3
【4】函数的返回值可以是一个函数
def add(x, y):
return x + y
def bar():
return add
func = bar()
print(func) # <function add at 0x00000239EC363E20>
res = func(1, 2)
print(res) # 3
【二】闭包函数
【1】什么是闭包
定义:闭包是指在函数内部定义的函数,并且该函数内部可以访问外部函数的变量。
-
闭包是指包含对自由变量的函数和对这些变量的引用环境的组合。
-
基于函数对象的概念,可以将函数返回到任意位置去调用
-
但作用域的关系是在定义完函数时就已经被确定了的,与函数的调用位置无关。
# 定义全局变量
x_global = 1
# 定义外层函数
def outer():
def inner():
print(x_global)
return inner
def func():
x_func = 3
# 调用f1()返回函数f2
inner = outer()
# 需要按照函数定义时的作用关系去执行,与调用位置无关
inner()
func() # 结果为1
闭包的特点
1.内部函数可以访问外部函数的变量:闭包中的内部函数可以引用外部函数中定义的变量,即使外部函数已经执行完毕,这些变量仍然会保留在内存中。
2.外部函数返回内部函数:通常情况下,外部函数会将内部函数作为返回值返回给调用者,从而形成一个闭包。
3.闭包保持了对外部变量的引用:由于闭包中的内部函数引用了外部变量,所以这些外部变量不会被垃圾回收机制回收,而是保存在闭包中。
闭包构成特点
1. 函数嵌套
2. 内部函数能够使用外部函数的变量(包括外部函数接收的参数)
3. 外部函数返回内部函数的引用。
【2】什么是闭包函数
闭:就是函数内部定义的参数,至少要有两层函数
包:内部函数要使用外部函数名称空间中的名字
只有同时满足两个或以上才能称之为闭包函数
调用和引用
从代码书写格式来看,函数调用就是在函数名后加上括号(),引用就是不加括号;函数调用时会立即执行函数,而引用时不会执行。
从深层次来看,函数引用实际上就是将这个函数的内存地址赋给了某个变量。这样就可以通过某个变量来调用这个函数了。
需要注意的是,在赋值过程中不要加上括号,因为加上括号会直接执行该函数并将结果赋给变量。而我们想要的是将整个函数作为对象进行传递和操作。
- 也就是说函数被当做数据处理时,始终以自带的作用域为准。
- 若内嵌函数包含对外部函数作用域(而非全局作用域)中变量的引用
- 那么该’内嵌函数’就是闭包函数,简称闭包(Closures)
# 定义全局变量
x_global = 1
def outer():
# 定义局部变量,覆盖全局变量
x_global = 2
def inner():
# 打印外部函数的局部变量
print(x_global)
return inner
func = outer()
func()
# 结果为2
【3】如何查看闭包函数所包裹的外部变量
- 可以通过函数的closure属性,查看到闭包函数所包裹的外部变量
# 定义全局变量
x_global = 1
def outer():
# 定义局部变量,覆盖全局变量
x_global = 2
def inner():
# 打印外部函数的局部变量
print(x_global)
return inner
func = outer()
func()
# 结果为2
res_first = func.__closure__
print(res_first) # (<cell at 0x000001945A08B9A0: int object at 0x0000019459AA0110>,)
print(dir(func.__closure__[0]))
'''
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
'''
# __closure__ 属性是一个元组,包含了函数闭包中的每个 cell 对象。每个 cell 对象都有一个 cell_contents 属性,它存储着相应的值。
res_second = func.__closure__[0].cell_contents
print(res_second) # 2
- “闭”代表函数是内部的,“包”代表函数外’包裹’着对外层作用域的引用。
- 因而无论在何处调用闭包函数,使用的仍然是包裹在其外层的变量。
【4】闭包函数用途
(1)保持状态
-
保持状态: 闭包可以用来保持函数调用之间的状态。
-
目前为止,我们得到了两种为函数体传值的方式
- 一种是直接将值以参数的形式传入
- 另外一种就是将值包给函数
[1]将值以参数的形式传入
import requests
# 将值以参数的形式传入
def get(url):
return requests.get(url).text
[2]将值包给函数
import requests
# 将值包给函数
def page(url):
def get():
return requests.get(url).text
return get
[3]对比
- 方式一在下载同一页面时需要重复传入url
- 方式二只需要传一次值,就会得到一个包含指定url的闭包函数,以后调用该闭包函数无需再传url
import requests
# 将值以参数的形式传入
def get(url):
return requests.get(url).text
# 方式一下载同一页面
get('https://www.python.org')
get('https://www.python.org')
get('https://www.python.org')
import requests
# 将值包给函数
def page(url):
def get():
return requests.get(url).text
return get
# 方式二下载同一页面
python = page('https://www.python.org')
python()
python()
python()
(2)函数工厂
- 函数工厂: 闭包允许创建函数工厂,即可以动态生成函数。
- 在你的例子中,
page
函数就是一个函数工厂,它返回一个根据传入的url
动态生成的函数。
import requests
# 将值包给函数
def page(url):
def get():
return requests.get(url).text
return get
python = page('https://www.python.org')
java = page('https://www.java.com')
(3)封装
- 封装: 闭包可以用来实现类似面向对象编程中的封装概念。
- 通过将函数和其相关的状态(变量)捆绑在一起,形成一个封闭的单元。
def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter1 = counter()
counter2 = counter()
print(counter1()) # 1
print(counter1()) # 2
print(counter2()) # 1
扩展:
用途:爬虫
1.3 闭包函数的用途
爬虫:爬取百度首页的数据
import requests
def outer(url):
# url = 'https://www.jd.com/'
def get_content():
# url = 'https://www.jd.com/'
res=requests.get(url)
res.encoding='utf-8'
# print(res.text) # 返回的是文本
print(res.content) # 返回的是文本
with open('baidu.html', 'wb') as f:
f.write(res.content)
return get_content
res=outer('https://www.jd.com/') # res:get_content
res()
res()
res()
res()
res()
res1=outer('https://www.taobao.com/')
res1()
res1()
res1()
res1()
res1()
res1()
res1()
本文来自博客园,作者:Unfool,转载请注明原文链接:https://www.cnblogs.com/queryH/p/17896706.html
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!