day03.23迭代器
迭代器
什么是迭代:
迭代其实就是指更新换代,但是每一次迭代的过程都需要依赖于上一次的结果。
迭代器:
迭代器是用来迭代取值的工具。而迭代是重复反馈过程的活动,其目的通常是为了逼近所需的目标或结果;每一次对过程的重复都称为一次迭代,而每一次迭代得到的结果会作为下一次迭代的初始值;因此,单纯的重复并不是迭代。
eg:
# 单纯的循环并不是迭代,即下一次循环并没有用到上一次的迭代结果 import time while True: print(123) time.sleep(0.1)
# 属于迭代,即下一次的迭代需要用到上一次迭代的结果 n = 1 while True: print(n) n += 1 # 迭代取值 l1 = [11, 22, 33, 44, 55] n = 0 while n < len(l1): print(l1[n]) ''' 11 22 33 44 55 ''' n += 1
可迭代对象:
从python的语法形式上讲,内置有__iter__方法(双下iter方法)的对象都是可迭代对象。
尝试调用__iter__方法,可以查看数据是否为可迭代对象。例如字符串、列表、元组、字典、集合、打开的文件都是可迭代对象。
i = 11 # 整型不是 f = 11.11 # 浮点型不是 s = 'jason' # 字符是 l = [1,2,3,4] # 列表是 d = {'name':'jason','age':18} # 字典是 t = (1,2,3,4) # 元组是 se = {1,2,3,4,5} # 集合是 b = True # 布尔值不是 f = open() # 文件是 def index():pass # 普通函数不是
可迭代对象提供了除了索引取值外的另一种取值方法,相较于索引取值来说,二者各有优劣。
迭代器对象:
- 可迭代对象调用__iter__方法之后生成的结果就是迭代器对象。
- 迭代器是Python提供的一种统一的、不依赖于索引的迭代取值方式,只要存在多个“值”,无论序列类型还是非序列类型都可以按照迭代器的方式取值。
- 迭代器对象是内置有__iter__和__next__方法的对象,如果对迭代器对象执行__iter__方法,得到的仍然是迭代器本身;而如果对迭代器执行__next__方法,得到的就是迭代器下一次计算的值。
- 迭代器对象能够极大的节省内存空间。
- 迭代器对象取值时直接调用__next__方法即可,但是需要注意迭代器取值结束之后继续取值会报错!!!(字典和集合for循环取值的底层都是使用的迭代器取值)
ps:
- 许多的双下方法都有简写方式,二者是等价的。例如__iter__等价于iter();__next__等价于next()。
s = 'jason' print(s.__iter__()) print(iter(s)) print(s.__len__()) print(len(s))
- note:有些迭代器对象本身也是可迭代对象,比如文件!!!
- 可迭代对象调用一次__iter__方法迭代变成器对象;如果继续调用__iter__方法,其结果还是迭代器对象本身。
s = 'jason' res = s.__iter__() # 此时已经是迭代器对象 res1 = s.__iter__().__iter__().__iter__() # 对迭代器对象进行双下iter方法后,还是迭代器对象本身 print(res, res1) # <str_iterator object at 0x10762bdd8> <str_iterator object at 0x107636dd8>
eg:迭代取值要点,注意区别迭代对象和迭代器对象。
s = 'jason' print(s.__iter__().__next__()) # j 每次先产生一个新的迭代器对象然后取值 print(s.__iter__().__next__()) # j 每次先产生一个新的迭代器对象然后取值 print(s.__iter__().__next__()) # j 每次先产生一个新的迭代器对象然后取值 print(s.__iter__().__next__()) # j 每次先产生一个新的迭代器对象然后取值 res = s.__iter__() # 已经变成迭代器对象了 print(res.__iter__().__next__()) # j 之后再调用还是自身 print(res.__iter__().__next__()) # a print(res.__iter__().__next__()) # s print(res.__iter__().__next__()) # o
for循环的内部原理和本质
for循环的底层原理就是迭代器,其内部结构如下:
for 变量名 in 可迭代对象: 循环体代码
- 会将in后面的数据调用__iter__()变成迭代器对象
- 针对产生的迭代器对象依次调用__next__()方法迭代取值
- 当值取完之后,会自动处理报错并退出循环
eg:
# 不依赖于for循环 完成对列表元素的取值 l1 = [11, 22, 33, 44, 55, 66, 77, 88] res = l1.__iter__() # 迭代对象运用__iter__方法变为迭代器对象 n = 0 while n < len(l1): print(res.__next__()) # 对迭代器对象进行迭代取值 n += 1
# 利用while与异常捕获 实现for循环的功能 info = {'name': 'jason', 'age': 18, 'pwd': 123} # 1.先转换成迭代器对象 # res = info.__iter__() res = iter(info) # 2.迭代取值 while True: # print(res.__next__()) try: print(next(res)) except StopIteration as e: # 结束while循环 break
迭代取值和索引取值的优劣
迭代取值:
优点:
- 兼容所有的容器类型,为序列和非序列类型提供了一种统一的迭代取值方式。
- 迭代器可以很大程度的节省内存空间。惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用__next__来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。
缺点:
- 取值的顺序永远都是从左往右 并且无法重复获取,取完就结束了
- 除非取尽,否则无法获取迭代器的长度
索引取值:
优点:可以反复获取相同的元素,并且没有固定的方向,可以一次取到任意想取的元素
缺点:只能支持有序的容器类型,无序的无法取值,其兼容性没有迭代取值高
异常处理
异常又称为bug,即代码运行出错之后就是异常,异常会导致程序立刻停止 。
异常信息的组成部分:
Traceback (most recent call last): File "/Users/jiboyuan/PycharmProjects/day16/05 异常处理.py", line 3, in <module> name NameError: name 'name' is not defined ''' line关键字所在的那一行,用来提示是那一行代码出错 NameError提示代码的错误的类型 name 'name' is not defined就是指描述代码错误的具体原因 '''
异常的分类:
异常分为语法结构异常和逻辑异常两种。其中语法异常时低级错误,是不被允许存在的错误。
异常的类型:
eg:异常的类型有很多种
print(name) # NameError 名字错误 l1 = [11, 22, 33] print(l1[100]) # IndexError 索引错误 d = {'name': 'jason'} print(d['age']) # KeyError 键错误 int('jason') # ValueError 值错误
异常处理的操作:
通过代码来处理跳过异常错误,使整个代码能够继续运行下去。
基本的语法结构:
try: # 可能会出错的代码 except '错误的类型1' as e: # e指代的就是错误的提示信息 # 针对性的处理措施 except '错误的类型2' as e: # e指代的就是错误的提示信息 # 针对性的处理措施 except '错误的类型3' as e: # e指代的就是错误的提示信息 # 针对性的处理措施
万能的语法结构:
try: '可能会出错的代码' except Exception as e: '统一的处理措施'
异常处理的原则:
- 被检测的代码越少越好
- 能尽量少用就尽量少用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?