news 2026/4/16 9:18:58

【Python零基础到进阶】装饰器与生成器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Python零基础到进阶】装饰器与生成器

包含编程资料、学习路线图、源代码、软件安装包等!【[点击这里]】!

属性控制

一、基础方法属性化
1# 1. 传统方法控制2classTest:3def__init__(self):4self._text='我不想让你看见'56# 显式操作接口7defget_t(self):8returnself._text910defset_t(self,value):11self._text=value1213defdel_t(self):14delself._text151617# 使用示例18a=Test()19print(a.get_t())# 调用并查看属性20print(a._text)# 也可以直接调用属性21a.set_t('新值')# 显式调用方法修改属性值22print(a.get_t())# 输出:新值23a.del_t()# 删除属性24print(a.get_t())# 删除后调用,报错:AttributeError: 'Test' object has no attribute '_text'

传统方法的问题;

✔️ 每次操作都要记方法名
✔️ 可以直接访问a._text不安全
✔️ 代码不够简洁直观

二、property()函数进阶
1classTest:2""" 3 保持原有方法不变 4 """5def__init__(self):6self._text='我不想让你看见'78defget_t(self):9returnself._text1011defset_t(self,value):12self._text=value1314defdel_t(self):15delself._text1617# 把三个方法打包成属性18x=property(get_t,set_t,del_t)192021# 实例化对象22a=Test()23""" 24 a.x 将触发 getter方法, 25 a.x = value 将触发 setter方法, 26 del a.x 触发 deleter方法. 27 """28print(a.x)# 隐式调用get_t → 输出:我不想让你看见29a.x='马甲属性'# 隐式调用set_t(value),设置属性30print(a.x)# 隐式调用get_t → 输出:马甲属性31dela.x# 隐式调用del_t 删除属性32print(a.x)# 调用已删除的属性


解决的问题:
✔️ 用属性语法替代方法调用
✔️ 隐藏真实属性名_text
✔️ 保持数据验证能力(可在方法中添加检查)

1classTest:2def__init__(self):3self._text='我不想让你看见'45# 带异常处理的访问器6defget_t(self):7try:8returnself._text9except:10return'属性不存在'1112defset_t(self,value):13self._text=value1415defdel_t(self):16delself._text1718x=property(get_t,set_t,del_t)192021a=Test()22print(a.x)23a.x='我穿上了马甲'24print(a.x)25dela.x26print(a.x)# 输出:属性不存在


解决的问题:
✔️ 增加了异常捕获,在访问不存在的属性时可以不报AttributeError的错误。

三、property()函数的装饰器使用方法
1classTest:2def__init__(self):3self._text='我不想让你看见'45# @property 修饰了text()方法,这样就使得该方法变成了text属性.6# 需要注意的是,如果类中只包含该方法,那么text属性将是一个只读属性7@property# 替代get_t8deftext(self):9try:10returnself._text11except:12return'访问属性不存在'1314# 而要想实现修改text属性的值,还需要为text属性添加 setter 方法,15# 就需要用到 setter 装饰器,它的语法格式如下:16@text.setter# # 替代set_t17deftext(self,value):18self._text=value1920# 除此之外,还可以使用 deleter 装饰器来删除指定属性,其语法格式为:21@text.deleter# 替代del_t22deftext(self):23delself._text2425a=Test()26print(a.text)# 无需括号,和属性完全一致2728a.text='我又换马甲了'# 直接赋值29print(a.text)3031dela.text# 直接删除32print(a.text)


方法优势:
✔️ 每个操作对应一个装饰器
✔️ 方法名即属性名,更直观
✔️ 方便添加类型检查等逻辑

五、property()函数语法总结
注意>定义顺序要求:
1classDemo:2@property3defattr(self):# ① 定义getter4returnself._value56@attr.setter# ② 定义setter(必须引用已存在的attr)7defattr(self,value):8self._value=value910@attr.deleter# ③ 定义deleter11defattr(self):12delself._value


错误用法示例:

1classErrorDemo:2@attr.setter# ❌ 未先定义@property3defattr(self,value):4self._value=value56@property7defattr(self):8returnself._data910@attr.deleter11defattr(self):12pass# ❌ 方法名不一致

装饰器

1deffunc1(a):2print(a)# ① 打印外层参数3print("函数 func1 正在执行")4deffunc2(b):5print(b)# ③ 打印内层参数6print("函数 func2 正在执行")7returna+b# ④ 访问外层变量8returnfunc2# ② 返回内层函数910# 调用方式一(分步执行)11f=func1(1)# 触发① → 返回func212print(f)# 输出:<function func1.<locals>.func2 at 0x...>13c=f(2)# 触发③④ → 返回314print(c)# 输出:31516# 调用方式二(链式调用)17c=func1(1)(2)# 依次触发①③④18print(c)# 输出:3

闭包与装饰器的关联:

3.使用装饰器和不使用装饰器的区别
通过计算函数运行时间来对比下
非装饰器写法:

1importtime23deftimer(func):4print('开始计时')# ① 开始计时标记5start=time.time()# ② 记录开始时间6func()# ③ 执行原函数7end=time.time()# ④ 记录结束时间8print('计时结束')# ⑤ 结束计时标记9returnf'一共花费了{end-start}秒的时间'# ⑥ 返回计时结果1011defour_func():12n=013foriinrange(1000001):14n+=i15print('装饰器的计时工具')# ⑦ 原函数执行标记16print(n)# ⑧ 输出计算结果17returnn1819# 调用方式20t=timer(our_func)# 必须显式调用timer21print(t)# 输出计时结果


装饰器用法:
装饰器的本质是一个闭包函数 🔻

1importtime23deftimer(func):# ① 接受被装饰函数4defcall():# ② 定义包装函数5print('开始计时')# 16start=time.time()7n=func()# ③ 执行原函数8end=time.time()9print('计时结束')# 310print(f'一共花费了{end-start}秒的时间')11returnn# ④ 返回原函数结果12returncall# ⑤ 返回包装函数1314@timer# ⑥ 应用装饰器15defour_func():16n=017foriinrange(1000001):18n+=i19print('装饰器的计时工具')# 220returnn212223# 使用装饰器:相当于省略了这步>our_func = timer(our_func)24t=our_func()25print(t)

运行结果:

区别总结:

  1. 调用方式
  1. 代码侵入性
  1. 功能复用性
  1. 设计原则

4.语法糖
什么是语法糖?

1defdecor(func):2defname():3print("被装饰的函数 add 即将执行")4func()5print("被装饰的函数 add 已执行完毕")6returnname78defadd():9print("函数 add 正在执行 ")1011# 手动包装函数12add=decor(add)# 等价于 @decor13add()# 调用包装后的函数


语法糖写法

1defdecor(func):2defname():3print("被装饰的函数 add 即将执行")4func()5print("被装饰的函数 add 已执行完毕")6returnname78@decor# 语法糖应用9defadd():10print("函数 add 正在执行 ")1112# 直接调用13add()# 自动触发装饰器逻辑


区别总结:
1.装饰器调用方式

1@decordefadd():...

2.代码简洁性

5.为什么需要装饰器?

1# 累加操作2defadd(a):3start_time=time.time()# 计时逻辑4total=05foriinrange(0,a):6total+=i7end_time=time.time()8exe_time=end_time-start_time9print(f'累加操作,花费的时间是{exe_time}')# 计时逻辑10returntotal1112# 累乘操作13defmul(a):14start_time=time.time()# 计时逻辑15product=116foriinrange(1,a):17product*=i18end_time=time.time()19exe_time=end_time-start_time20print(f'累乘操作,花费的时间是{exe_time}')# 计时逻辑21returnproduct

代码调用:

1# 累加的调用2total=add(100001)3print(total)# 输出:500005000045# 累乘的调用6product=mul(100001)7print(product)# 输出:累乘结果(非常大)

装饰器实现方法:
定义装饰器

1importtime23defdecorat(func):4defwrapper(a):# 定义包装函数5start_time=time.time()6result=func(a)# 执行原函数7end_time=time.time()8exe_time=end_time-start_time9print(f'该操作,花费的时间是{exe_time}')10returnresult# 返回原函数结果11returnwrapper

使用装饰器

1@decorat2defadd(a):3print('开始执行累加操作:')4total=05foriinrange(0,a):6total+=i7returntotal89@decorat10defmul(a):11print('开始执行累乘操作:')12product=113foriinrange(1,a):14product*=i15returnproduct

代码调用

1# 累加操作2f=add(100001)3print(f)# 输出:500005000045# 累乘操作6g=mul(100001)7print(g)# 输出:累乘结果(非常大)

生成器
1.什么是生成器?

2.案例说明:依次打印 0-1000 的数字

1defabc():2lyst=[]3foriinrange(1001):4lyst.append(i)5returnlyst67foriinabc():8print(i)

1defgen():2foriinrange(1001):3yieldi45foriingen():6print(i)

1a=(iforiinrange(1001))2foriina:3print(i)

3.生成器的优势
4.生成器的第一种定义方式(函数式生成器)

生成器的第一种定义方式是通过 函数加 yield 关键字 来定义。
普通函数 vs 生成器

普通函数:
1defintNum(n):2print("开始执行")3foriinrange(n):4returni5print("继续执行")67num=intNum(5)8print(num)# 输出:09num=intNum(5)10print(num)# 输出:011num=intNum(5)12print(num)# 输出:0

问题:

生成器:
1defintNum(n):2print("开始执行")3foriinrange(n):4yieldi5print("继续执行")67num=intNum(5)8print(next(num))# 输出:开始执行 09print(next(num))# 输出:继续执行 110print(next(num))# 输出:继续执行 211print(next(num))# 输出:继续执行 312print(next(num))# 输出:继续执行 413print(next(num))# 抛出 StopIteration 异常

优势:

1print(next(intNum(5)))# 输出:开始执行 02print(next(intNum(5)))# 输出:开始执行 03print(next(intNum(5)))# 输出:开始执行 0

错误原因>>>每次调用 intNum(5) 都会创建一个新的生成器对象,无法保留状态。

while 循环定义生成器

1deffib(max):2n=03whilen<max:4yieldn5n+=167a=fib(9)8print(next(a))# 输出:09print(next(a))# 输出:110print(next(a))# 输出:211print(next(a))# 输出:312print(next(a))# 输出:413print(next(a))# 输出:514print(next(a))# 输出:615print(next(a))# 输出:716print(next(a))# 输出:817print(next(a))# 抛出 StopIteration 异常


说明:

1deffib(max):2a,b=0,13whilea<max:4yielda5print('---')6a,b=b,a+b
1# 使用生成器输出斐波那契数列2a=fib(15)3print(next(a))# 输出:04print(next(a))# 输出:15print(next(a))# 输出:16print(next(a))# 输出:27print(next(a))# 输出:38print(next(a))# 输出:59print(next(a))# 输出:810print(next(a))# 输出:1311print(next(a))# 抛出 StopIteration 异常


说明:

遍历生成器输出斐波那契数列
1forninfib(15):2print(n)

5.生成器的第二种定义方式(生成器表达式)

1.基本语法:
2.基本示例:
1g=(iforiinrange(100))2print(g)# 输出:<generator object <genexpr> at 0x...>34# 遍历生成器5foriing:6print(i)
3.加条件筛选:
1# 只生成能被 3 整除的数2g=(iforiinrange(100)ifi%3==0)3print(g)# 输出:<generator object <genexpr> at 0x...>45# 遍历生成器6foriing:7print(i)
4.带条件判断的生成器推导式
1# 小于 10 的数直接输出,否则输出 '哈哈'2g=(iifi<10else'哈哈'foriinrange(100))3print(g)# 输出:<generator object <genexpr> at 0x...>45# 遍历生成器6foriing:7print(i)
5.对比列表推导式

生成器推导式与列表推导式的语法非常相似,但它们的返回值不同:

1# 生成器推导式2g=(iifi<10else'哈哈'foriinrange(100))3print("返回生成器对象:",g)# 输出:<generator object <genexpr> at 0x...>45# 列表推导式6g_list=[iifi<10else'哈哈'foriinrange(100)]7print("返回列表对象:",g_list)# 输出:[0, 1, 2, ..., 9, '哈哈', '哈哈', ...]


🟢总结

🟡文末福利

🔴包含编程资料、学习路线图、源代码、软件安装包等!【点击这里】领取!

可以扫描下方二维码领取【保证100%免费

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 1:19:58

全国地级市旧海关(1842-1949)

数据简介CNPaperData本数据以Jin和Schulze&#xff08;2025&#xff09;《The long-term effect of western customs institution on firm innovation in China》的研究框架为参考&#xff0c;构建全国地级市旧海关虚拟变量。旧海关是近代中国对外开放与制度转型的关键节点&…

作者头像 李华
网站建设 2026/3/31 17:17:34

ChatGPT 说:ChatGPT-5.2的革新:AI如何从工具进化为智能伴侣?

2025年12月9日&#xff0c;OpenAI发布了备受瞩目的ChatGPT-5.2版本。作为AI技术的一次重大突破&#xff0c;ChatGPT-5.2不仅在性能上做出了质的提升&#xff0c;更在人机互动、情感理解和多领域应用上展现出前所未有的潜力。这一版本的发布&#xff0c;预示着人工智能正从传统的…

作者头像 李华
网站建设 2026/4/11 22:40:42

Gitee:2025年中国企业研发管理的数字化转型引擎

Gitee&#xff1a;2025年中国企业研发管理的数字化转型引擎 在数字化转型浪潮席卷全球的当下&#xff0c;项目管理软件已成为企业提升研发效率的关键基础设施。作为国内领先的一站式研发管理平台&#xff0c;Gitee&#xff08;码云&#xff09;凭借其本土化服务优势、全链路功能…

作者头像 李华
网站建设 2026/4/16 2:06:51

国产DevSecOps工具崛起:数字化转型的安全新引擎

国产DevSecOps工具崛起&#xff1a;数字化转型的安全新引擎 在数字经济加速发展的今天&#xff0c;软件开发安全已成为国家战略的重要组成部分。随着《网络安全法》《数据安全法》等法规的深入实施&#xff0c;DevSecOps正从技术概念转变为产业实践&#xff0c;而国产工具在这场…

作者头像 李华
网站建设 2026/4/12 3:42:06

参考文献怎么找:实用方法与技巧指南

① WisPaper&#xff08;文献聚类 术语辅助&#xff09; 官网&#xff1a;https://www.wispaper.ai 帮助快速理解陌生领域的核心概念和研究主题。 ② Elicit 自动列出最相关论文和方法&#xff0c;为跨学科快速扫文献提供便利。 ③ Explainpaper 逐段解释论文内容&#xff0c…

作者头像 李华
网站建设 2026/4/15 2:25:06

文献查询:高效获取学术资源的方法与技巧探讨

① WisPaper&#xff08;文献聚类 术语辅助&#xff09; 官网&#xff1a;https://www.wispaper.ai 帮助快速理解陌生领域的核心概念和研究主题。 ② Elicit 自动列出最相关论文和方法&#xff0c;为跨学科快速扫文献提供便利。 ③ Explainpaper 逐段解释论文内容&#xff0c…

作者头像 李华