python之迭代器与异常处理

可迭代对象

在了解可迭代对象之前,我们要想了解什么叫做迭代。

在执行重复的步骤时,每一次的结果都要依赖上一个的结果计算,这个过程就叫做迭代。

# 迭代过程
n = 0
while n < 5:
    print(n)
    n += 1

所以,可迭代对象其实简单的来说就是可以放到for循环里进行遍历的数据,像列表、字典、元组、字符串等等

如果在pycharm中想要查看一个数据是否是可迭代对象,我们可以看看这个数据是否可以调用__iter__方法。

可以调用:会提示

image

不可以调用:不会提示

image

属于可迭代对象的数据类型:

列表、字典、元组、集合、字符串、文件

不属于可迭代对象的数据类型:

整型、浮点型、布尔值、函数

迭代器对象

一个可迭代对象在调用__iter__方法后返回的结果就是迭代器对象,迭代器对象可以极大的节省存储空间,它只会在需要用的时候才会取出数据。

迭代器对象能调用__iter__方法和__next__方法,所以迭代器对象一定是可迭代对象,但可迭代对象不一定是迭代器对象。

image

迭代器对象的取值方法

迭代器对象可以用__next__方法取值,每次可以取出一个值,取完了继续取值会报错。

s = 'hello'
# 将可迭代对象变为迭代器对象
res = s.__iter__()
# 调用__next__方法
print(res.__next__())  # 输出:h
print(res.__next__())  # 输出:e
print(res.__next__())  # 输出:l
print(res.__next__())  # 输出:l
print(res.__next__())  # 输出:o
print(res.__next__())  # 报错StopIteration

也可以使用next方法,等价于__next__

s = 'hello'
# 将可迭代对象变为迭代器对象
res = iter(s)
# 调用__next__方法
print(next(res))  # 输出:h
print(next(res))  # 输出:e
print(next(res))  # 输出:l
print(next(res))  # 输出:l
print(next(res))  # 输出:o
print(next(res))  # 报错StopIteration

取值注意事项

"""可迭代对象不要在调用__iter__的同时调用__next__,不然在下一次调用__next__还是只会输出第一个值"""
s = 'hello'
print(s.__iter__().__next__())  # 输出:h
print(s.__iter__().__next__())  # 输出:h
print(s.__iter__().__next__())  # 输出:h

"""如果一个迭代器对象调用__iter__并不会有任何反应,返回的还是它本身"""
s = 'hello'
res = s.__iter__()
print(res.__iter__().__next__())  # 输出:h
print(res.__iter__().__next__())  # 输出:e
print(res.__next__())  # 输出:l

for循环内部原理

如过此时有一串数据,我们如何不使用for循环将它输出?是不是只能使用while循环输出了?

实现:

s = 'hello'
n = 0
res = iter(s)
while n < len(s):
    print(next(res))
    n += 1

这时候需要一个变量来判断是否输出完毕,而for循环并不需要额外的变量。

原理

首先我们要了解for循环的语法结构

for 变量名 in 可迭代对象:
    循环语句
  1. 在执行for循环时,for循环会先将可迭代对象变为迭代器对象,也就是调用__iter__方法。
  2. 使用迭代器对象的__next__方法依次取值并赋值给变量名
  3. 当值取完后,自动处理报错并退出循环。

前两步的使用while循环表现为:

s = 'hello'
res = s.__iter__()
while True:
    print(res.__next__())

第三步的报错该怎么处理,这就是我们接下来要学习的内容。

image

异常处理

异常就是报错,报错就说明代码有问题,报错的同时程序也会立刻停止运行,异常处理就可以防止报错时程序会停止的问题。

异常信息的组成部分

异常信息有三部分组成。

  • Traceback部分:可以知道报错的位置
  • error部分:可以知道错误类型
  • 报错原因:可以知道为什么会报错

image

异常的分类

异常主要分为语法异常和逻辑异常两大类。

  • 语法异常:语法结构问题,比如if的语法结构写错,小白经常会犯的错误。
  • 逻辑异常:代码逻辑出现问题,比如字符串类型调用了不属于它的方法。

异常的类型

常见错误类型,只列举部分。

异常类型 原因
NameError 没有声明过的变量被使用了
IndexError 没有此索引
KeyError 没有此键(key)
ValueError 无效参数
ImportError 导入模块错误
SyntaxError 语法错误
TypeError 数据类型错误
IndentationError 缩进错误
AttributeError 调用了错误的方法
StopIteration 迭代器没有更多的值了

image

异常处理实操

对于代码中可能出现错误的代码,我们可以进行处理让代码不会报错,防止程序停止。

语法结构(括号内的语法可以被省略):

try:
    可能会出错的代码
except 错误类型1 (as 变量名): # 错误的信息会赋值给变量名
    处理措施
except 错误类型2 (as 变量名): # 错误的信息会赋值给变量名
    处理措施
...

如果不知道错误类型,还可以这么写:

try:
    可能会出错的代码
except Exception (as 变量名): # 错误的信息会赋值给变量名
    处理措施
except Exception (as 变量名): # 错误的信息会赋值给变量名
    处理措施
...

实操:

# 案例一:代码会出错
try:
    res = int('a')
    print(res)
except Exception as e:
    print('代码出错啦')
    print(e)  
"""
运行结果:
代码出错啦
invalid literal for int() with base 10: 'a'
"""

# 案例二:代码不会出错
try:
    res = int('5')
    print(res)
except Exception as e:
    print('代码出错啦')
    print(e)  
"""
运行结果:
5
"""

异常处理原则:不要把全部代码全部写入try中,虽然代码不会报错了,但你的功能也无法实现了,异常处理只适用于检测代码,能不用就不用

image

异常处理的其他操作

结合else使用:如果try语句里的代码没有异常,则执行else里的代码。

try:
    res = int('5')
    print(res)
except Exception as e:
    print(e)  
else:
    print('代码正常运行结束了')
"""
运行结果:
5
代码正常运行结束了
"""

结合finally使用:无论try语句里的代码如何,最后都会执行finally里的代码。

# 案例一:代码没有异常
try:
    res = int('5')
    print(res)
except Exception as e:
    print(e)  
finally:
    print('代码结束了')
"""
运行结果:
5
代码结束了
"""

# 案例二:代码有异常
try:
    res = int('abc')
    print(res)
except Exception as e:
    print(e)  
finally:
    print('代码结束了')
"""
运行结果:
invalid literal for int() with base 10: 'abc'
代码结束了
"""

主动报错:使用raise关键字,强行报错,报错原因可以自行填写。

raise NameError('我就要报错!!!')
# 报错:NameError: 我就要报错!!!

断言(了解即可):使用assert关键字,后面跟判断条件,条件成立则跳过,不成立就会报错。

name = 'jason'
assert isinstance(name, str)
# 无事发生

name = 'jason'
assert isinstance(name, int)
# 报错:AssertionError

for循环本质

了解了异常处理了现在应该明白了for循环的本质了吧!

# for循环
s = 'jason'
for i in s:
    print(i)

"""利用while与异常捕获 实现for循环的功能"""
s = 'jason'
# 1.先转换成迭代器对象
res  = s.__iter__()
# 2.迭代取值
while True:
    # 3.异常处理
    try:
        print(res.__next__())
    except StopIteration as e:
        # 4.结束while循环
        break

迭代取值与索引取值的区别

  • 迭代取值

    优点:兼容所有的容器类型。

    缺点:无法重复取值,只能按顺序取值(从左到右),取一个少一个。

  • 索引取值

    优点:可以精确反复取值。

    缺点:只能取有序的容器类型。

image

posted @ 2022-03-23 16:30  Yume_Minami  阅读(226)  评论(0编辑  收藏  举报