python迭代和异常处理
可迭代对象
#迭代的定义:
迭代就是指更新换代 要重复进行 而且每次的迭代都必须基于上一次的结果
我们使用for循环的时候就是把元素从容器里一个个取出来
这种过程其实就是迭代
#迭代器:
迭代取值的工具
'迭代器的作用是提供给你一种不依赖索引取值的方式'
#需要迭代取值的数据类型:
字符串、列表、元组、字典、集合
#可迭代对象
内置有__iter__方法的都可以称之为是可迭代对象
1.大白话理解就是数据可以通过点的方式点出来__iter__
2.__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 = with open ('test.txt','w',encoding='utf-8' # 文件是
def index():pass # 普通函数不是
'文件对象本身就是迭代器对象(所以文件对象执行内置的__iter__之后还是本身,没有任何变化)'
迭代器对象
# 什么是迭代器对象?
可迭代对象调用__iter__方法之后生成的结果就是迭代器对象
# 迭代器对象的特征
含有__iter__方法和__next__方法
# 如何理解迭代器对象
迭代器对象能够极大的节省存储空间
eg:类似于哆啦A梦的口袋 不用的时候就是一个口袋的面积 用的时候可以从中取出很多数据
''' 迭代器一定是可迭代对象
可迭代对象不一定是迭代器对象
迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身'''
#迭代器取值的特点
只能往后依次取,不能从后往前取
#代码示例:
l1 = [1, 2, 3, 4]
res = l1.__iter__() #用__iter__将可迭代对象转换成一个迭代器对象
print(res.__next__()) # 迭代器取值,调用__next__
print(res.__next__()) # 调用一次取一个
print(res.__next__())
print(res.__next__())
print(res.__next__()) # 如果取完了直接报错StopIteration
#迭代器的简写:
__方法名__ 等价 方法名()
最为常见的两个是
__iter__ iter()
__next__ next()
for循环内部原理
for循环里的in关键字,跟的是一个可迭代对象,将in后面的对象调用__iter__转换成迭代器
#for循环内部的本质
1.让关键字in后面的对象使用__iter__转换成迭代器对象
2.调用__next__迭代取值
3.内部有异常捕获StopIteration,当迭代器里的元素为空时报错,自动结束循环
#代码示例:
l1 = [11,22,33,44,55,66,77,88]
'''需求:不依赖于for循环 完成对列表元素的取值'''
res = l1.__iter__()
n = 0
while n < len(l1):
print(res.__next__())
n += 1
"""
for循环底层原理
for 变量名 in 可迭代对象:
循环体代码
1.会将in后面的数据调用__iter__()变成迭代器对象
为什么文件对象也可以for循环 因为本身就是迭代器对象 再次调用不变
2.针对产生的迭代器对象依次调用__next__()方法迭代取值
3.当值取完之后 会自动处理报错并退出循环
"""
res = l1.__iter__()
while True:
print(res.__next__())

异常处理
# 异常的定义:
代码运行出错之后就是异常 异常会导致程序立刻停止
异常就是程序运行时发生错误的信号
# 报错代码示例:
Traceback (most recent call last):
File "E:/PyCharm 2021.2.3/jbr/bin/E/PycharmProjects/pythonProject2/day11.py", line 8, in <module>
name
NameError: name 'name' is not defined
1.line关键字所在的一行
用于提示你代码哪一行出错了 点击前面的蓝色字体可以直接定位
'''如果报错的信息很长 一般最后一个才是'''
2.NameError错误的类型
代码的报错也可以分为很多类型
3.name 'name' is not defined
具体的报错原因(就是解决报错的答案)

# 异常的分类
1.语法异常
不被允许的 如果出现了必须立刻改正
eg:if分支结构都不会写...
if 1, while :,...
2.逻辑异常
可以允许的 如果出现了尽快修改即可
eg:代码动态获取到了一个字符串类型的数据但是调用了列表的内置方法
name = 'jason'
print(name.append())
'语法错误跟异常处理无关 处理异常之前必须避免语法上的错误'
# 异常的类型:
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
TypeError 传入对象类型与要求的不符合
ValueError 值错误
异常处理实操
'''有时候针对可能会出错的代码 也可以自己提前写好处理措施'''
正常情况下代码出错 肯定是直接导致程序停止
但是也可以自己通过代码来处理 从而避免程序的停止
#part1:基本语法
try:
被检测的代码块
except 异常类型:
try中一旦检测到异常,就执行这个位置的逻辑
#part2:单分支
'单分支只能用来处理指定的异常情况 如果未捕获到异常 则报错'
try:
a
except NameError as e: #我们可以使用except与as+变量名 搭配使用,打印变量名会直接输出报错信息
print(e) #name 'a' is not defined
#part3:多分支
try:
可能会出错的代码
except 错误的类型1 as e: # e指代的就是错误的提示信息
针对性的处理措施
except 错误的类型2 as e: # e指代的就是错误的提示信息
针对性的处理措施
except 错误的类型3 as e: # e指代的就是错误的提示信息
针对性的处理措施
...
# part4:万能类型
很多时候可能自己都不知道会报什么类型的错误
'''万能异常:常见的报错都可以照单全收'''
try:
可能会出错的代码
except Exception as e:
统一的处理措施
#异常处理使用准则
1.被检测的代码越少越好
2.能尽量少用就尽量少用
异常处理了解
# 结合else使用
当try检测的代码没有发生异常 正常运行完毕之后执行else的子代码
try:
可能会出错的代码
except Exception as e:
统一的处理措施
else:
可能会出错的代码没有出错 最后走else子代码
# 结合finally使用
无论try检测的代码是否有异常 最后都会执行finally子代码
try:
name
except Exception as e:
print(e)
finally:
无论try检测的代码是否有异常 最后都会执行finally子代码
# 模板
try:
name
except Exception as e:
print(e)
else:
print('正常完毕执行')
finally:
print('最后都会执行')
# 断言(了解中的了解)
name = 'jason'
assert isinstance(name,str)
# 主动报错(需要掌握)
raise NameError('主动报错!')
'''由于是主动报错 所以可以非常明确的知道错误的类型'''
for循环的本质
#代码示例:
'利用while与异常捕获 实现for循环的功能'
l1 = [11.1, 2, 'jason', {'age': 18}]
res =l1.__iter__() # 1.先转换成迭代器对象
while True: # 2.迭代取值
try:
print(next(res))
except Exception as e:
print(e.args)
break # 结束while循环
迭代取值与索引取值的对比
1.索引取值
优势:可以反复获取相同的元素 并且没有固定的方向
劣势:只能支持有序的容器类型 无序的无法取值兼容性没有迭代取值高
2.迭代取值
优势:兼容所有的容器类型
劣势:取值的顺序永远都是从左往右 并且无法重复获取 取完就完了
# 真正底层的迭代取值后续可能很少用 一般都是for循环代替
"""
迭代器里面的东西是固定的 没取一个就会少一个 取完就空了
"""
