day03.24
生成器
生成器对象(自定义迭代器)
若函数体包含yield关键字,再调用函数,并不会执行函数体代码,得到的返回值即生成器对象。
生成器的本质还是一个迭代器,只不过是我们自己写的自定义函数代码。生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器,也可以叫自定义迭代器。
生成器对象也是节省存储空间的;特性与迭代器对象一致。生成器与迭代器的最重要的区别就是有没有yield关键字。
当函数体代码中含有yield关键字,第一次调用函数并不会执行函数体代码,而是将函数变成了生成器。
def index(): print('你还记得我吗?') yield 123 yield 123, 111 print('是不是忘记我了!!!') yield 666 print(index) # <function index at 0x1096c0ea0> 没有调用之前 就是一个普通的函数 res = index() # 加括号调用并接收结果:不执行代码,而是变成生成器对象(迭代器) print(res) # <generator object index at 0x11da33468> print(res.__next__()) # 123 变成生成器对象之后调用__next__就会开始执行函数体代码,yield有点像return的功能 print(res.__next__()) # (123, 111) 开始下一次yield执行程序,yield有点像return的功能 print(res.__next__()) # 666 print(res.__next__()) # 报错 # 程序执行完毕再次取值会报错
ps:
当函数体代码中含有yield关键字时,第一次调用函数并不会执行函数体代码,而是将函数变成了生成器。
如果函数体代码中含有多个yield关键字,执行一次__next__返回后面的值,并且让代码停留在yield位置;
再次执行__next__基于上次的位置继续往后执行到下一个yield关键字处,如果没有了,继续再执行也会报错。
自定义range方法
range方法其实是一个可迭代对象。
# 通过生成器模拟range方法 def my_range(start, end=None, step=1): if not end: # 没有给end传值 my_range(10) end = start start = 0 while start < end: yield start start += step for i in my_range(1, 100): print(i)
yield关键字
- 在函数体代码中出现 可以将函数变成生成器
- 在执行过程中 可以将后面的值返回出去 类似于return
- 还可以暂停住代码的运行
- 还可以接收外界的传值(了解)
def eat(name): print(f'{name}准备干饭') while True: food = yield print(f'{name}正在吃{food}') res = eat('赵公子') # 想执行一次代码 如果想执行多次直至结束 可以直接用for循环 res.__next__() res.__next__() # 赵公子正在吃None res.__next__() # 赵公子正在吃None res.send('生日蛋糕') # 可以给yield传值 并且自动调用一次__next__方法 res.send('大鸡腿') # 可以给yield传值 并且自动调用一次__next__方法
生成器表达式
# 生成器对象也是为了节省存储空间,在后期我们做代码优化的时候,可以考虑使用 res = (i for i in 'jason') print(res) # <generator object <genexpr> at 0x1130cf468> print(res.__next__()) """生成器内部的代码只有在调用__next__迭代取值的时候才会执行""" # 普通的求和函数 def add(n, i): return n + i # 生成器对象 返回 0 1 2 3 def test(): for i in range(4): yield i # 将test函数变成生成器对象 g = test()
模块
什么是模块?
模块就是一系列功能的结合体,可以直接使用。
eg:import.time 导入模块
time.time() 调用模块
为什么要使用模块?
模块能够极大的提升开发效率!!!
将程序模块化会使得程序的组织结构清晰,维护起来更加方便;程序中的模块可以被重复使用,使用模块既保证了代码的重用性,又增强了程序的结构性和可维护性。
在Python中,一个py文件就是一个模块,文件名为xxx.py模块名则是xxx,导入模块可以引用模块中已经写好的功能。
模块的三种来源
- 内置的模块
内置模块是解释器自带的模块,无需下载,使用时直接导入使用即可
- 自定义模块
自定义模块就是指自己写的代码,然后封装成模块,自己用或者发布到网上供别人使用
- 第三方模块
别人写的发布到网上的程序模块,是可以下载使用的模块
模块的四种表现形式
- 使用python代码编写的py文件
- 多个py文件组成的文件夹(包)
- 已被编译为共享库或DLL的c或C++扩展(了解)
- 使用C语言编写并链接到python解释器的内置模块(了解)
模块的两种导入方式
模块想要使用,必须要提前导入,只有先导入才能使用。
import...句式
impord md格式
# 运行执行文件,产生一个当前文件的名称空间 import md # 执行import句式,导入模块文件(即执行模块文件代码产生模块文件的名称空间) print(md.name) # 在当前文件的名称空间中产生一个模块的名字,指向模块的名称空间;通过该名字就可以使用到模块名称空间中的所有数据 md.read1() # 找到模块文件当中的read1()
ps:相同的模块被重复导入只会执行一次!!!
import md # 有效 import md # 无效(写了跟没写一样) import md # 无效(写了跟没写一样)
import句式的特点:
可以通过import后面的模块名点加变量名的方式,使用模块中所有的名字,并且不会与当前名称空间中的名字冲突。即导入模块当中的变量名可以和当前执行文件当中的变量名相同。
from...import...句式
from md import name格式
# 运行执行py文件当中的程序代码,产生一个名称空间 from md import name # 导入模块当中的一个name变量名,执行导入语句,运行模块文件产生名称空间存放运行过程中的所有名字,将import后面的名字直接拿到当前执行文件中 print(name) # jasonNB # 查找模块当中的变量名name所指代的具体内容 name = 'kevin' print(name) # kevin # py文件当中的变量名称name print(money) # 报错 只能使用模块当中的name
ps:此句式下重复导入也只会导入运行一次,重复导入会作废。
from...import句式的特点:
- 使用from...import的句式,只能调用import后面出现的名字
- 使用模块名称空间中的名字不需要加模块名前缀,直接使用即可
- 使用from...import的句式会产生名字冲突的问题,在使用的时候一定要避免名字冲突
导入模块句式的补充
- 可以给模块起别名(使用频率很高)
import md as m print(m.name) from md import name as n # 变量名复杂,可以简写 print(n)
- 可以连续导入多个模块或者变量名
import time, sys, md from md import name, read1, read2 ''' 连续导入多个模块 这多个模块最好有相似的功能部分 如果没有建议分开导入 如果是同一个模块下的多个变量名无所谓!!! '''
- 通用导入from md import *
*表示md里面所有的名字;
如果模块文件中使用了__all__限制可以使用的名字,那么*号就会失效,则依据__all__后面列举的名字使用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?