news 2026/9/21 22:08:51

Python装饰器入门:从闭包到@wraps

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python装饰器入门:从闭包到@wraps

Python学习笔记-Day9-装饰器篇

函数的使用

首先回顾一下前面学过的函数:

def hi(name='yasoob'): return 'hi ' + name greet = hi print(greet())

在python中,一切皆对象

在函数里定义函数

#方法一、 def a(name = 'youzi'): print('youzi') def greet(): return 'now greet() function' def welcome(): return 'now welcome() function' print(greet()) print(welcome()) print('now a() function') hi() #方法二、 #这里如果也可以写成: def a(name='youzi'): def greet(): return 'now greet() function' def welcome(): return 'now welcome() function' if name == 'youzi': return greet else: return welcome num = a(name='ddd') num1 = a(name='youzi') print(num()) print(num1())

这里解释方法二细节:

  1. name='youzi’是默认参数,当不填的时候,就是youzi
  2. retrun greet:这里greet是对象,当加上括号,就调用执行了这个函数
  3. num = a(name=‘ddd’):实例化a,然后传入参数ddd,并赋值给num,然后再通过判断传入的值来,返回相应的值
  4. 其实如果当函数不加括号,就可以到处传递,并且可以赋值给别的变量,而不去执行它。!!!
  5. 这里其实我们如果调用函数,不传参的话,默认就是youzi,然后就会返回greet,这个时候我们可以这么写,a()(),就是调用greet
  6. 当我把num = a(name=‘zhangsan’),那么就会返回welcome函数

重要点

函数里面的函数,如果没有调用就不会被执行,只有调用的时候才会执行
函数里面的函数只能在函数里面的函数调用,不能在函数的外部调用
从函数中返回函数,其实就是调用函数
变量也可以接收函数,但是函数一般分别两种,一种是带括号的叫调用函数并且执行,另一种是不带括号的叫对象

#定义一个函数名叫hi def hi(): #返回的是hi yasoob return 'hi yasoob' #定义一个函数,但是因为我们今天要讲的是装饰器,所以func这个的作用其实是用来接收函数的,当然也可以接收变量、字典、列表参数等 def doSomethingBeforeHi(func): print('I am doing some boring work before executing hi()') a = func() #这个其实是调用我们传过来的函数,因为加了括号 print(a) doSomethingBeforeHi(hi)

函数里定义函数,然后在函数里调用函数

双层嵌套函数,并且调用另一个函数

def a_new_decorator(a_func): def wrapTheFunction(): print("I am doing some boring work before executing a_func()") #调用传递过来的函数 a_func() print("I am doing some boring work after executing a_func()") #这个return的作用在于触发函数,并且调用函数 return wrapTheFunction def a_function_requiring_decoration(): print("I am the function which needs some decoration to remove my foul smell") a_function_requiring_decoration() #print(a_new_decorator(a_function_requiring_decoration)) a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) a_function_requiring_decoration()

总结:

可以函数里面定义函数,当然也可以相互传递函数,函数的参数也可以接收函数

接下来,开始进装饰器,这个时候讲装饰器就会好理解点,博客当时学这个也是很头大,不知道为什么这样做?后面发现之后,感觉还挺有意思的

@符号来使用装饰器

这里先提前解释:
在装饰函数的时候,其实就已经做了一个动作,就是把下面的函数名,传给了装饰的函数(定义的装饰函数),如果不理解接着往下看

演示

def a_new_decorator(a_func): def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction @a_new_decorator def a_function_requiring_decoration(): print("I am the function which needs some decoration to remove my foul smell") #把a_function_requiring_decoration放到a_new_decorator装饰,但是装饰不会调用 a_new_decorator(a_function_requiring_decoration) a_function_requiring_decoration()
def a_new_decorator(a_func): def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction @a_new_decorator def a_function_requiring_decoration(): print("I am the function which needs some decoration to remove my foul smell") print(a_function_requiring_decoration.__name__) >>wrapTheFunction 封装函数 >>这里我们想打印原函数的名字,所以接下来我们需要使用@wraps

使用wraps来保持原函数的名字

#从functools库导入函数 from functools import wraps #定义一个函数,添加一个参数f,用来接收函数 def decorator_name(f): #让原函数保持不变 @wraps(f) #这个是语法规范,参数是固定死的,函数名不是,可以随便改,但是要符合命名规范 def decorated(*args,**kwargs): #判断can_run,如果是True就不执行,是false就执行 if not can_run: return "Functions will not run" #把原函数的参数和输入的内容都返回回去 return f(*args,**kwargs) #返回decorated,作用是调用并执行函数 return decorated #使用装饰器 @decorator_name def func(): return ("Functions is running") can_run = True print(func()) can_run = False print(func())

return func(*args,**kwargs) 的核心作用:
动态调用函数:func可以是任何函数
传递所有参数:*args传递所有位置参数,也就是元组,**kwargs传递所有关键字参数,也就是字典
保持透明性:装饰器不需要知道被装饰函数的具体函数
返回结果:将原始函数的返回值原样返回

闭包

再说一个知识点,那就是闭包

解释:通俗来说,闭包就是函数及其周边环境的组合。(在本文语境下,你可以暂时理解周边环境就是一些外部的变量)

闭包通常涉及到一个内部函数,内部函数可以访问或者说记住外部函数的局部变量,即使外部函数已经执行完毕。

代码如下:

# 创建一个装饰器,名为simple_decorator,里面func可以理解为参数也是函数 def simple_decorator(func): def wrapper(): print("--------开始-------") func() print("--------结束-------") #触发wrapper,也就是调用该函数 return wrapper def greet(): print("您好!") closure = simple_decorator(greet) print(type(closure))

closure就是一个闭包的案例!

print("--------开始-------") func() print("--------结束-------") 本质上执行的函数代码 print("--------开始-------") greet() print("--------结束-------")
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/22 0:16:21

vsftpd 安装、升级、配置全流程总结(含问题解决方案)

一、遇到的核心问题总结在离线环境中,主要遇到以下问题:安装路径非默认:源码编译后 vsftpd 默认安装到/usr/local/sbin/vsftpd(而非/usr/sbin/),导致服务文件ExecStart路径不匹配,启动失败&…

作者头像 李华
网站建设 2026/9/22 0:20:10

HunyuanVideo-Foley部署:本地与云端GPU实战

HunyuanVideo-Foley部署:本地与云端GPU实战 在智能家居设备日益复杂的今天,确保无线连接的稳定性已成为一大设计挑战。蓝牙技术虽已发展至5.0版本,但实际应用中仍面临功耗、干扰和兼容性等问题。尤其在多设备共存的环境中,如何实现…

作者头像 李华
网站建设 2026/9/21 1:03:31

LangChain工具使用:简化AI函数调用

本章对应源代码:https://github.com/RealKai42/langchainjs-juejin/blob/main/lc-tools.ipynb 上一节中,我们学习了如何直接使用 openAI 的原生 API 去使用 function calling (tools)功能,需要自己维护历史、写参数类…

作者头像 李华
网站建设 2026/9/21 11:27:13

Docker 镜像打包为 tar 并在其他环境加载运行(离线部署实战指南)

Docker 镜像打包为 tar 并在其他环境加载运行(离线部署实战指南)适用场景:内网部署 / 无法访问 Docker Hub / 生产环境离线交付 阅读目标:掌握 Docker 镜像打包、传输、加载、运行的完整闭环一、为什么需要把 Docker 镜像打包成 t…

作者头像 李华
网站建设 2026/9/21 17:43:57

Docker 镜像体积优化实战:从 1GB 到 100MB

Docker 镜像体积优化实战:从 1GB 到 100MB适用人群:已经使用 Docker,有镜像体积焦虑的开发者 / 运维工程师 阅读目标:掌握 一套可复用的镜像瘦身方法论,而不是零散技巧一、为什么 Docker 镜像会变得这么大?…

作者头像 李华
网站建设 2026/9/21 8:21:14

LobeChat能否分配任务?团队协作智能调度

LobeChat能否分配任务?团队协作智能调度 在现代企业中,一个常见的场景是:产品经理在群里说“帮我把昨天会议里的三个需求整理成文档”,接着有人手动打开 Notion,翻找聊天记录,复制粘贴、重新组织语言——整…

作者头像 李华