网站首页 > 资源文章 正文
在Python中,闭包(Closure)是一种强大的功能,在函数式编程中,他能提供非常灵活的功能组合。它允许在一个函数内部定义另一个函数,并且内部函数可以访问外部函数的变量。
这些外部变量的值在内部函数被定义时就确定了,即使在外部函数的执行结束后,这些值依然可以被内部函数访问。
什么是闭包
闭包通常由两部分组成:
- 外部函数:定义了一个或多个内部函数。
- 内部函数:可以访问并操作外部函数的局部变量。
def outer(x):
def inner(y):
return x + y
return inner
# 使用闭包
add_five = outer(5)
print(add_five(10)) # 输出: 15
在这个例子中,outer是一个外部函数,它接收一个参数x,并定义了一个内部函数inner,该函数也接收一个参数y,并返回x + y的结果。然后,outer返回inner。当调用outer(5)时,它会返回一个新函数,这个新函数可以访问outer中的x变量(这里是5),并且可以像普通函数一样被调用。
如果你想在内部函数中对外部传过来的变量进行修改
def counter():
count = 0
def increment():
count += 1
return count
return increment
c = counter()
print(c())
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value
是的,它报错了,外部函数的变量无法在内部直接修改,这时候我们需要使用nonlocal关键字
def counter():
count = 0
def increment():
nonlocal count # 声明 count 不是局部变量,而是外部函数的变量
count += 1
return count
return increment
c = counter()
print(c()) # 1
print(c()) # 2
print(c()) # 3
闭包的应用场景
闭包是 Python 中一种强大的特性,它在装饰器、状态保存和封装等场景中非常有用。
装饰器本质上是一个Python函数,是一种特殊的闭包
它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。
有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
举个例子
def get_score(score):
return ('今年我的成绩是:%s'%score)
现在有个新需求,把去年的成绩也打印出来,于是我们就添加记录去年成绩的代码。
def get_score(score):
print('去年成绩:58')
return ('今年我的成绩是:%s'%score)
这样也可以,但是如果我们有许多这样的函数,总不能一个个的手动修改吧,这个时候,为了减少重复写代码,我们可以这样做,重新定义一个函数:记录去年的信息 ,之后再执行真正的业务代码。
def last_info():
print('去年成绩:58')
def get_score(score):
last_info()
return ('今年我的成绩是:%s'%score)
score1=get_score(55)
print(score1)
去年成绩:58
今年我的成绩是:55
嗯,这样看起来就优雅多了,
但是这样有很大风险,因为直接在函数内部增加一个函数,破坏了函数的完整性,如果大量修改很容易导致函数出问题。
那么装饰器这时候应该登场了,
Python中支持了@语法糖,直接放在函数上面而不必修改函数内部,这种写法优雅而美观,保证了函数完整性。
def last_info(func):
def inner(*args,**kwargs): #位置参数and关键字参数,可表示任意参数
print('去年成绩:58')
return func(*args,**kwargs)
return inner
@last_info
def get_score(score):
return ('今年我的成绩是:%s'%score)
这样就高级了,而且只是在函数上面增加一个函数,完全不需要对函数内部进行修改。
但是这样有一个问题
print(get_score.__name__) #
输出:inner
get_score函数的名字为何会变成了inner?
因为装饰器最终会返回一个可调用对象,而这个可调用对象才是正在最后被执行的,所以get_score被装饰器修饰后,得到的是inner这个函数(函数是可调用对象),于是乎get_score.__name__实际上是inner._name_。
那该怎么解决这个问题呢,加上wraps注解。
from functools import wraps
def last_info(func):
@wraps(func) #这样可以保持函数的名称不被修改
def inner(*args,**kwargs): #位置参数and关键字参数,可表示任意参数
print('去年成绩:58')
return func(*args,**kwargs)
return inner
@last_info
def get_score(score):
return ('今年我的成绩是:%s'%score)
print(get_score.__name__)
输出:get_score
这里wraps本身也是一个装饰器,这个装饰器是一个带参数的装饰器,参数本身就是get_score函数。在获取get_score函数元信息时,实际上还是在执行inner._name_,但是inner有wraps装饰器,最终元信息是通过wraps装饰器返回的,wraps装饰器对get_score函数做了份拷贝,所以拿到的还是get_score函数的元信息。
建议写装饰器时都加上wraps注解,这是一个好习惯。
带参数的装饰器
上面我们说的装饰器都是没有参数的,只能输出定义好的去年成绩,无法修改。
现在有一个需求,比如:使用装饰器的时候可以输入去年的成绩。
装饰器还有更强大的功能,比如带参数的装饰器,装饰器允许我们在使用它时提供参数输入,这使得装饰器的功能更加有灵活性。
def last_info(score):
def inner(func):
def wapper(*args,**kwargs):
print('去年成绩:%s'%score)
return func(*args,**kwargs)
return wapper
return inner
@last_info(88)#带参数
def get_score(score):
return ('今年我的成绩是:%s'%score)
#调用
score=get_score(100)
print(score)
去年成绩:88
今年我的成绩是:100
上面的lase_info就是一个可以输入参数的装饰器,其实他是装饰器外面在嵌套一个函数,并返回装饰器,我们也可以把他理解为一个带参数的闭包。
总的来说,装饰器的理念是对原函数、对象的功能进行加强,而且是在不破坏原函数内部结构的基础上进行功能加强,相当于对函数的重新封装。
猜你喜欢
- 2025-03-12 JavaScript 装饰器:从入门到进阶
- 2025-03-12 深入浅出Python装饰器:让代码魔法般升级的秘籍
- 2025-03-12 微信隐藏表白代码大全,微信满屏表情代码,万圣节表白专场
- 2025-03-12 你还在用Excel做大屏吗?这几款工具做大屏很不错
- 2025-03-12 解锁鸿蒙装饰器:应用、原理与优势全解析
- 2025-03-12 实例讲解Ruby使用设计模式中的装饰器模式的方法
- 2025-03-12 Python快速入门教程11:高级特性之装饰器
- 2025-03-12 Ollama简明教程
- 2025-03-12 手把手教你用DeepSeek+即梦AI制作专属情人节海报
- 2025-03-12 网页首屏设计不漂亮,五招借鉴过来(大量案例)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 电脑显示器花屏 (79)
- 403 forbidden (65)
- linux怎么查看系统版本 (54)
- 补码运算 (63)
- 缓存服务器 (61)
- 定时重启 (59)
- plsql developer (73)
- 对话框打开时命令无法执行 (61)
- excel数据透视表 (72)
- oracle认证 (56)
- 网页不能复制 (84)
- photoshop外挂滤镜 (58)
- 网页无法复制粘贴 (55)
- vmware workstation 7 1 3 (78)
- jdk 64位下载 (65)
- phpstudy 2013 (66)
- 卡通形象生成 (55)
- psd模板免费下载 (67)
- shift (58)
- localhost打不开 (58)
- 检测代理服务器设置 (55)
- frequency (66)
- indesign教程 (55)
- 运行命令大全 (61)
- ping exe (64)
本文暂时没有评论,来添加一个吧(●'◡'●)